[스탠포드 iOS] 5강 뷰에 나타내기
5강 목표
- Error Handling
- Any
- Keywords
- Custom Drawing
- Enum
Error Handling
// 통상적인 방법
do {
try context.save()
} catch let error {
throw error
}
// 100% 확률로 error가 발생하지 않을 때 사용 (보통 사용하지 않는다.)
try! context.save()
// 심각하지 않은 error일 경우
try? context.save()
Any & AnyObject
- 다양한 타입이 될 수 있다.
- 이 수업에서 데이터 구조를 사용할 때 Any를 사용하면 안 된다.
as?
키워드를 통해 Any를 명시한 타입으로 변환한다.
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
// sender가 UIButton, UITableViewCell일 수도 있기 때문에 Any 타입이다.
// sender가 nil일 수도 있기 때문에 Optional로 선언
let vc: UIViewController = ConcentrationViewController()
if let cvc = vc as? ConcentrationViewController {
cvc.flipCard()
}
// vc는 UIViewController 여서 flipCard() 메소드를 사용할 수 없다.
// 하지만 다운캐스팅을 통해서 사용할 수 있다.
Other Interesting Classes
NSObject
- Objective-C의 모든 클래스의 루트 클래스
- Swift에서는 NSObject의 서브 클래스가 될 필요가 없다.
NSNumber
- Objective-C에서 숫자를 전달할 때 사용한다.
- API에서가 등장했다면 Int, Double형이라고 생각해도 무방하다.
Date
- 날짜나 시간을 표현한다.
- Calendar, DateFormatter, DateComponents 등과 종종 같이 쓰인다.
Data
- iOS API간의 데이터 전달에 사용한다.
- bit를 담은 가방
Views
- iOS 클래스인 UIView의 서브클래스
- 좌표계를 정의하는 화면의 사각형
- 계층 구조
- 그래픽적으로 구현된다. 하지만 코드로도 작성 가능하다.
func addSubView(_ view: UIView)
func removeFromSuperview()
// 추가할 때는 superview에서 요청
// 제거할 때는 제거될 view에게 요청
초기화
- 초기화는 최대한 피하려한다.
init(frame: CGRect) // 코드에서 뷰를 만드는 용도
init(coder: NSCoder) // 인터페이스 빌더에서 자유롭게 편집하고 앱이 실행될 때 초기화
// 두 가지를 모두 구현
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
awakeFromNib()
// 스토리보드로부터 UIView가 만들어졌을 때 호출된다.
좌표 시스템
CGFloat
- CG : CoreGraphic
- 그림을 그릴 때 CGFloat 타입을 사용한다. (부동소수점)
CGPoint
- CGFloat 타입인 x, y가 들어가있는 구조체
CGSize
- CGFloat 타입의 width, height가 들어가있는 구조체
CGRect
- Rectangle 직사각형을 의미
- CGPoint, CGSize를 가지고 있는 구조체
// 통상적인 방법
do {
try context.save()
} catch let error {
throw error
}
// 100% 확률로 error가 발생하지 않을 때 사용 (보통 사용하지 않는다.)
try! context.save()
// 심각하지 않은 error일 경우
try? context.save()
Any & AnyObject
- 다양한 타입이 될 수 있다.
- 이 수업에서 데이터 구조를 사용할 때 Any를 사용하면 안 된다.
as?
키워드를 통해 Any를 명시한 타입으로 변환한다.
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
// sender가 UIButton, UITableViewCell일 수도 있기 때문에 Any 타입이다.
// sender가 nil일 수도 있기 때문에 Optional로 선언
let vc: UIViewController = ConcentrationViewController()
if let cvc = vc as? ConcentrationViewController {
cvc.flipCard()
}
// vc는 UIViewController 여서 flipCard() 메소드를 사용할 수 없다.
// 하지만 다운캐스팅을 통해서 사용할 수 있다.
Other Interesting Classes
NSObject
- Objective-C의 모든 클래스의 루트 클래스
- Swift에서는 NSObject의 서브 클래스가 될 필요가 없다.
NSNumber
- Objective-C에서 숫자를 전달할 때 사용한다.
- API에서가 등장했다면 Int, Double형이라고 생각해도 무방하다.
Date
- 날짜나 시간을 표현한다.
- Calendar, DateFormatter, DateComponents 등과 종종 같이 쓰인다.
Data
- iOS API간의 데이터 전달에 사용한다.
- bit를 담은 가방
Views
- iOS 클래스인 UIView의 서브클래스
- 좌표계를 정의하는 화면의 사각형
- 계층 구조
- 그래픽적으로 구현된다. 하지만 코드로도 작성 가능하다.
func addSubView(_ view: UIView)
func removeFromSuperview()
// 추가할 때는 superview에서 요청
// 제거할 때는 제거될 view에게 요청
초기화
- 초기화는 최대한 피하려한다.
init(frame: CGRect) // 코드에서 뷰를 만드는 용도
init(coder: NSCoder) // 인터페이스 빌더에서 자유롭게 편집하고 앱이 실행될 때 초기화
// 두 가지를 모두 구현
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
awakeFromNib()
// 스토리보드로부터 UIView가 만들어졌을 때 호출된다.
좌표 시스템
CGFloat
- CG : CoreGraphic
- 그림을 그릴 때 CGFloat 타입을 사용한다. (부동소수점)
CGPoint
- CGFloat 타입인 x, y가 들어가있는 구조체
CGSize
- CGFloat 타입의 width, height가 들어가있는 구조체
CGRect
- Rectangle 직사각형을 의미
- CGPoint, CGSize를 가지고 있는 구조체
as?
키워드를 통해 Any를 명시한 타입으로 변환한다.func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
// sender가 UIButton, UITableViewCell일 수도 있기 때문에 Any 타입이다.
// sender가 nil일 수도 있기 때문에 Optional로 선언
let vc: UIViewController = ConcentrationViewController()
if let cvc = vc as? ConcentrationViewController {
cvc.flipCard()
}
// vc는 UIViewController 여서 flipCard() 메소드를 사용할 수 없다.
// 하지만 다운캐스팅을 통해서 사용할 수 있다.
NSObject
- Objective-C의 모든 클래스의 루트 클래스
- Swift에서는 NSObject의 서브 클래스가 될 필요가 없다.
NSNumber
- Objective-C에서 숫자를 전달할 때 사용한다.
- API에서가 등장했다면 Int, Double형이라고 생각해도 무방하다.
Date
- 날짜나 시간을 표현한다.
- Calendar, DateFormatter, DateComponents 등과 종종 같이 쓰인다.
Data
- iOS API간의 데이터 전달에 사용한다.
- bit를 담은 가방
Views
- iOS 클래스인 UIView의 서브클래스
- 좌표계를 정의하는 화면의 사각형
- 계층 구조
- 그래픽적으로 구현된다. 하지만 코드로도 작성 가능하다.
func addSubView(_ view: UIView)
func removeFromSuperview()
// 추가할 때는 superview에서 요청
// 제거할 때는 제거될 view에게 요청
초기화
- 초기화는 최대한 피하려한다.
init(frame: CGRect) // 코드에서 뷰를 만드는 용도
init(coder: NSCoder) // 인터페이스 빌더에서 자유롭게 편집하고 앱이 실행될 때 초기화
// 두 가지를 모두 구현
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
awakeFromNib()
// 스토리보드로부터 UIView가 만들어졌을 때 호출된다.
좌표 시스템
CGFloat
- CG : CoreGraphic
- 그림을 그릴 때 CGFloat 타입을 사용한다. (부동소수점)
CGPoint
- CGFloat 타입인 x, y가 들어가있는 구조체
CGSize
- CGFloat 타입의 width, height가 들어가있는 구조체
CGRect
- Rectangle 직사각형을 의미
- CGPoint, CGSize를 가지고 있는 구조체
func addSubView(_ view: UIView)
func removeFromSuperview()
// 추가할 때는 superview에서 요청
// 제거할 때는 제거될 view에게 요청
init(frame: CGRect) // 코드에서 뷰를 만드는 용도
init(coder: NSCoder) // 인터페이스 빌더에서 자유롭게 편집하고 앱이 실행될 때 초기화
// 두 가지를 모두 구현
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
awakeFromNib()
// 스토리보드로부터 UIView가 만들어졌을 때 호출된다.
CGFloat
- CG : CoreGraphic
- 그림을 그릴 때 CGFloat 타입을 사용한다. (부동소수점)
CGPoint
- CGFloat 타입인 x, y가 들어가있는 구조체
CGSize
- CGFloat 타입의 width, height가 들어가있는 구조체
CGRect
- Rectangle 직사각형을 의미
- CGPoint, CGSize를 가지고 있는 구조체
- 원점은 좌측 상단에 있다.
- 단위는 points
- pixels : 스크린을 구성하고 있는 작은 점
contentScaleFactor
: point에 얼마나 많은 pixel이 존재하는지 확인
bounds
⭐️- CGRect타입의 변수
- drawing을 할 때 항상 사용한다.
frame
- drawing과는 전혀 상관이 없다.
- 슈퍼뷰에서 어디에 위치하는지를 말한다.
center
- drawing과 상관이 없다.
- 슈퍼 뷰의 입장에서 뷰의 중심을 이야기한다.
- 회전을 보면 frame, center는 위치를 잡는 것과 관련이 있다.
- frame과 bounds과 같다고 생각하면 안 된다.
Custom Views
- 원하는 drawing을 하거나 원하는 터치 이벤트를 다룰 때 사용한다.
// UIView에서 오버라이드해서 구현 (이 방법뿐)
override func draw(_ rect: CGRect)
// 절대 직접 호출하면 안 된다.⭐️
// 새롭게 drawing하고 싶다면 아래의 메소드를 대신 호출
setNeedsDisplay()
setNeedsDisplay(_ rect: CGRect)
Core Graphics Concepts
- context를 기반으로 한다.
UIGraphicsGetCurrentContext()
: drawing할 context를 알려준다.
- 경로 설정 (line, arc, etc)
- drawing 속성 설정 (color, font, etc)
- 경로에 대해서는 테두리 그리기와 채워 넣기 중 하나를 선택한다.
UIBezierPath
// UIView에서 오버라이드해서 구현 (이 방법뿐)
override func draw(_ rect: CGRect)
// 절대 직접 호출하면 안 된다.⭐️
// 새롭게 drawing하고 싶다면 아래의 메소드를 대신 호출
setNeedsDisplay()
setNeedsDisplay(_ rect: CGRect)
UIGraphicsGetCurrentContext()
: drawing할 context를 알려준다.demo
ViewController.swift
class ViewController: UIViewController {
var deck = PlayingCardDeck()
override func viewDidLoad() {
super.viewDidLoad()
for _ in 1...10 {
if let card = deck.draw() {
print("\(card)")
}
}
}
}
// 카드덱을 만들어서 10개를 우선 콘솔에 출력한다.
PlayingCard.swift
// CustomStringConvertible을 활용하면 사용자가 정의한 description 형태가 출력된다.
struct PlayingCard: CustomStringConvertible {
var description: String {
return "\(rank)\(suit)"
}
var suit: Suit
var rank: Rank
enum Suit: String, CustomStringConvertible {
case spades = "♠️"
case hearts = "♥️"
case clubs = "♣️"
case diamonds = "♦️"
static var all = [Suit.spades, .hearts, .diamonds, .clubs]
var description: String {
return rawValue
}
}
enum Rank: CustomStringConvertible {
case ace
case face(String)
case numeric(Int)
var order: Int {
switch self {
case .ace: return 1
case .numeric(let pips): return pips
case .face(let kind) where kind == "J" : return 11
case .face(let kind) where kind == "Q" : return 12
case .face(let kind) where kind == "K" : return 13
default: return 0
}
}
// 각각의 케이스로 구현하면 13가지를 따로 다 적어줘야하지만 좋지 않은 방법이다.
// numberic -> 카드 2 ~ 카드 9
// face -> J, Q, K 이미지 사용하는데 where 사용이 특이했다.
// ⭐️ self를 kind 상수에 바인딩하고 where 조건절에서 조건에 해당하면 해당 값을 return한다.
static var all: [Rank] {
var allRanks: [Rank] = [.ace]
for pips in 2...10 {
allRanks.append(Rank.numeric(pips))
}
allRanks += [Rank.face("J"), .face("Q"), .face("K")]
return allRanks
}
var description: String {
switch self {
case .ace: return "A"
case .numeric(let pips): return String(pips)
case .face(let kind): return kind
}
}
}
}
PlayingCardDeck.swift
struct PlayingCardDeck {
private(set) var cards = [PlayingCard]()
// private(set) : setter에 대해서만 private 선언, 쓰기 속성 막아둠
// 초기화하면 모든 카드를 담는다.
init() {
for suit in PlayingCard.Suit.all {
for rank in PlayingCard.Rank.all {
cards.append(PlayingCard(suit: suit, rank: rank))
}
}
}
// 랜덤으로 카드하나를 return한다.
mutating func draw() -> PlayingCard? {
if cards.count > 0 {
return cards.remove(at: cards.count.arc4random)
} else {
return nil
}
}
}
동작 모습
class ViewController: UIViewController {
var deck = PlayingCardDeck()
override func viewDidLoad() {
super.viewDidLoad()
for _ in 1...10 {
if let card = deck.draw() {
print("\(card)")
}
}
}
}
// 카드덱을 만들어서 10개를 우선 콘솔에 출력한다.
// CustomStringConvertible을 활용하면 사용자가 정의한 description 형태가 출력된다.
struct PlayingCard: CustomStringConvertible {
var description: String {
return "\(rank)\(suit)"
}
var suit: Suit
var rank: Rank
enum Suit: String, CustomStringConvertible {
case spades = "♠️"
case hearts = "♥️"
case clubs = "♣️"
case diamonds = "♦️"
static var all = [Suit.spades, .hearts, .diamonds, .clubs]
var description: String {
return rawValue
}
}
enum Rank: CustomStringConvertible {
case ace
case face(String)
case numeric(Int)
var order: Int {
switch self {
case .ace: return 1
case .numeric(let pips): return pips
case .face(let kind) where kind == "J" : return 11
case .face(let kind) where kind == "Q" : return 12
case .face(let kind) where kind == "K" : return 13
default: return 0
}
}
// 각각의 케이스로 구현하면 13가지를 따로 다 적어줘야하지만 좋지 않은 방법이다.
// numberic -> 카드 2 ~ 카드 9
// face -> J, Q, K 이미지 사용하는데 where 사용이 특이했다.
// ⭐️ self를 kind 상수에 바인딩하고 where 조건절에서 조건에 해당하면 해당 값을 return한다.
static var all: [Rank] {
var allRanks: [Rank] = [.ace]
for pips in 2...10 {
allRanks.append(Rank.numeric(pips))
}
allRanks += [Rank.face("J"), .face("Q"), .face("K")]
return allRanks
}
var description: String {
switch self {
case .ace: return "A"
case .numeric(let pips): return String(pips)
case .face(let kind): return kind
}
}
}
}
struct PlayingCardDeck {
private(set) var cards = [PlayingCard]()
// private(set) : setter에 대해서만 private 선언, 쓰기 속성 막아둠
// 초기화하면 모든 카드를 담는다.
init() {
for suit in PlayingCard.Suit.all {
for rank in PlayingCard.Rank.all {
cards.append(PlayingCard(suit: suit, rank: rank))
}
}
}
// 랜덤으로 카드하나를 return한다.
mutating func draw() -> PlayingCard? {
if cards.count > 0 {
return cards.remove(at: cards.count.arc4random)
} else {
return nil
}
}
}
링크
Author And Source
이 문제에 관하여([스탠포드 iOS] 5강 뷰에 나타내기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@hhhan0315/스탠포드-iOS-5강-뷰에-나타내기
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Author And Source
이 문제에 관하여([스탠포드 iOS] 5강 뷰에 나타내기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@hhhan0315/스탠포드-iOS-5강-뷰에-나타내기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)