10. ㅇㅇ레알임
왜냐면
격주마다 언어가 바뀌면서 컴파일이 안됨
새로운 API (위젯과 쉐어 익스텐션)를 스위프트에서 사용하면 생소함 2배
스위프트에서 Objective-C를 사용하는 생소함
Objective-C에서 스위프트를 사용하는 생소함
Objective-C에서 스위프트를 사용한 것을 다시 스위프트에서 사용하고 디버그하는 생소함
격주마다 OSXDEV.org 코딩도장에서 문제를 내야하는 고통
12. CONTENTS
1. Objective-C와 Swift
2. Swift Optional
3. Swift Initailization
4. Swift Pattern Matching
5. Advanced Swift
6. Interoperability
7. 실제 사용 경험과 도입 전략
14. Objective-C
History
Brad Cox, Tom Love (Stepstone)
C언어에 Smalltalk의 특성을 더하기 위한 Pre-processor
1998년 NeXT가 라이센스 획득, GCC 지원
AppKit, FoundationKit, NeXTStep
MacOS X, iPhone iOS, UIKit
15. Objective-C
특성
C + Smalltalk = 마개조된 C언어
Strict Superset of C
Smalltalk-style messaging
!
메소드 호출이 아니라 메세징을 사용한다
16. C++ 메소드 호출
obj->method(argument);
컴파일 타임에 객체 obj의 클래스에 메소드 method가 있는지 확인
Compile-time binding
대부분의 Static-typing 객체지향 언어의 동작 방식 (Simula 계열)
17. Objective-C 메세징
[obj method: argument];
런타임에서 method:를 확인함
objc_msgSend(obj, @selector(method), argument)
C언어는 Static-typing 언어지만 메세징은 덕(Duck) 타이핑
클래스 타입이 메소드를 구현해야하는 것이 아니라
런타임에서 객체가 메세지를 받을 수 있으면 됨
18. 아닌데? 컴파일 안되는데?
[self ohMyGodMessage]; //컴파일 에러
물론 현대의 Objective-C 컴파일러는 메소드가 있는지 체크함
하지만 여전히 메소드의 레퍼런스를 가지고 오는 작업은 런타임에 행해짐
캐시 최적화 + 어셈블리로 구현됨
19. Dynamic 언어
언어의 여러 기능이 동적
[self performSelector:@selector(ohMyMessage)]; //경고
id myAnyObject
- (void)setMyValue:(id)foo; //AnyObject
false
20. 진짜 Dynamic
태초에는 id 타입 뿐이었음
-objectAtIndex:(NSUInteger)anIndex
{
…
}
뭔가 잘못된거 같지만 올바른 코드, 컴파일 됨
false
리턴타입을 정의안하면 자동으로 id 타입을 씀.
Objective-C의 초기엔 객체에 사용할 수 있는 유일한 타입이 id였음
22. Minimalistic
C언어의 규칙에 [ ]를 이용한 메세징이 규칙의 전부
C언어 (미니멀) + Smalltalk (미니멀) = 역시 미니멀
나머진 모두 관습(Convention)으로 해결한다!
프로퍼티 명명 규칙 myProperty, setMyProperty:
객체 생성 [[MyClass alloc] init] 도 특별한 것 없는 관습적인 메세징
KVO, KVC, Binding
24. 관습이 다 언어의 기능이 되었으니까
Objective-C의 관습과 보통 Strong-type 언어의 기능
Optional
Optional Binding (nil이 너무 많아)
Optional Chaining (nil이 너무 많아)
Implicitly Unwrapped Optionals (nil이 진짜 너무 많아)
Initialization
ARC
Enum
Tuple
Pattern Matching
Closure
Extensions
Protocols
25. 스위프트는 X언어랑 비슷하다
대략적인 기능을 볼 경우
스칼라랑 비슷하네. 인정
C#이랑 비슷하네. 인정
C#에서 F# (Ocaml)의 기능을 약간 가지고 왔네. 인정
Javascript랑 비슷하네. 이건 아님
!
보통 현재의 대세인 Strong, Static Type 프로그래밍 언어와 유사
31. null/nil
모든 레퍼런스 타입은 null이 가능하다
Java, C++, C, Objective-C, C#
!
NSString * = pointer to NSString or nil
char * = pointer to char or NULL
!
C#은 밸류타입에 null을 못넣는 문제를 극복하기 위해 nullable이라는 키워드를 추가
이는 부재를 의미하는 값에 대한 일관성을 높여주지만 Optional이 해결하는 문제와는 관계 X
32. 왜 null/nil이 나쁜가
하나 이상의 의미로 사용되기 때문
1.객체/레퍼런스/값이 초기화 되지 않은 상태
null
nil
NULL
[NSNull null]
-1
0
NSNotFound
INT_MAX
2.거짓이나 실패를 의미하는 값
38. Return Optional
Optional을 돌려주는 함수나 메소드
Objective-C의 많은 메소드들이 이렇게 변경됨
indexOfObject, toInt 등등
!
let age:Int? = mySomeString.toInt()
//Type Inference
let age = mySomeString.toInt()
39. Unwrapping Optional
Optional 타입에서 실제 값을 가지고 오는 작업
!
var age = mySomeString.toInt()
println(age!)
!
Int? 타입인 age가 만약 nil일 경우 런타임 에러가 발생
40. 안전하게 가지고 오는 방법
Optional Binding, if let =
if let ageValue = mySomeString.toInt() {
//이 블록에서만 Int 타입의 ageValue가 유효함
println(“나는 (ageValue)살 입니다”)
} else {
println(“나는 태어나지 않았습니다”)
}
41. F#, Ocaml, Swift
Option Type
type Option<'a> =
| Some of 'a
| None
스위프트와 동일하게 기본 타입은 null이 불가능
Option<string>으로 선언을 한 경우만 None 값을 넣을 수 있음
!
enum MyOptional<T> {
case None
case Some(T)
} //스위프트 Optional에 대한 pseudo 구현이지만 사실상 동일
// MyOptional<Int> => Int?
47. 초기화
무조건 해야함
var message: String
if sessionStarted {
message = “스위프트 세미나에 오신걸 환영합니다”
}
println(message) //컴파일 에러
48. 초기화
무조건 해야함
var message: String
if sessionStarted {
message = “스위프트 세미나에 오신걸 환영합니다”
} else {
message = “”
}
println(message)
49. Initializers
모든 프로퍼티를 초기화 해야한다
struct Color {
let red, green, blue: Double
init(grayScale: Double) {
green = grayScale
blue = grayScale
}
} //컴파일 에러: red 값이 초기화 되지 않음
50. Initializers
모든 프로퍼티를 초기화 해야한다
struct Color {
let red, green, blue: Double
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayScale
}
}
51. Initializers
프로퍼티가 초기화 되기 전에 self/this에 접근하는 메소드 사용 불가
struct Color {
let red, green, colour: Double
mutating func validateColor() { … }
init(grayScale: Double) {
red = grayScale
green = grayScale
validateColor()
blue = grayScale
}
} //error
52. Initializers
프로퍼티가 초기화 되기 전에 self/this에 접근하는 메소드 사용 불가
struct Color {
let red, green, colour: Double
mutating func validateColor() { … }
init(grayScale: Double) {
red = grayScale
green = grayScale
blue = grayscale
validateColor() //self에 접근 하는 메소드 모든 인자가 초기화 된 후 사용할 수 있다
}
}
53. Memberwise Initializers
struct Color {
let red, green, blue: Double
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
60. Designated and Convenience
두 종류의 생성자
Designated
모든 프로퍼티를 초기화 시키는 생성자
Designated 생성자는 부모 클래스의 Designated 생성자를 호출해야함
Convenience
최종적으로 Designated Initializer를 호출하는 짧은 생성자
다른 Convenience를 호출하여 Designated로 가도 됨
부모 클래스의 생성자를 호출 할 수 없음
67. Initailization 정리
초기화와 서브클래스 오버라이드
모든 값은 사용전에 초기화 되어야 한다
super.init 전에 모든 프로퍼티 값이 초기화 되어야 한다
Designated와 Convenience의 차이에 대해 알자
생성자가 상속되는 룰을 정확히 이해하자
!
서브클래스 없이 어떠한 Cocoa/Cocoa Touch 어플리케이션도 만들 수 없음!
72. 일단 지식을 적용해 봅시다
하지만 viewDidLoad에서 초기화 하고 싶은데?
왜냐면
self.view와 self.view.bounds 값을 사용할 수 있다
MyViewController()와 같이 객체 초기화 될 때가 아니라
화면에 표시될 때 UITableView를 초기화 하고 싶다
81. Implicitly Unwrapped Optional
불완전한 세상, nil을 사랑하는 Objective-C 레거시 프레임워크
Objective-C의 Foundation 프레임워크는 대부분 nil을 사용하기 때문에 너무 많은 if let이
나 ?를 피하기 위해 고육지책으로 있는 기능이라 생각 됨
84. Implicitly Unwrapped Optional
지양합시다
Optional 타입은 적을수록 좋다
Implicitly Unwrapped Optional은 옵셔널을 ‘쉽게’ 쓸 수 있게 해주는 기능
이 변수가 옵셔널인지 모르고 쓰다가 크래시 나기 쉽다
!
애플도 1.0으로 오면서 많은 인터페이스에서 !를 제거함
Implicitly Unwrapped Optionals는 필요악
88. Pattern Matching
Switch with Enum (and binding)
enum TrainStatus {
case OnTime
case Delayed(Int)
}
!
서로 다른 타입으로 Enum을 정의할 수 있음
F# (Ocaml)의 Discriminated Union
Recursive는 안됨
Enum은 중첩될 수 있으며 메소드도 가질 수 있음
96. UICollectionView Data Source
섹션별 아이템 개수를 정하는 델리게이트 메소드
-(NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section
!
스위프트
func collectionView(collecitonView: UICollectionView, numberOfItemsInSection
section: Int) -> Int
!
var numberOfItems = collectionView(self.collectionView, 0)
!
97. UICollectionView Data Source
스펙
섹션0은 아이템 개수 (<12개)
버튼이 안눌림
아이폰 3개
아이패드 8개
버튼이 눌림
아이템이 12개
섹션1은 버튼 개수 (<1개)
버튼이 안눌렸으면 1
눌렸으면 0
아이템은 서버에서 가지고 오며 보통 매일 다른 20개지만 개수를 보장할 수 없음
예외적인 경우 안보이는건 괜찮지만 크래시가 나지 않도록 할 것
99. 이런 메소드를 수백번씩 만들어왔다!
UITableView, UICollectionView
100. UICollectionView Data Source
패턴매칭으로 리팩토링
이 분기의 조건을 모두 모아 보면 모다?
섹션 section
현재 디바이스가 아이폰인가 아이패드인가 currentDeviceIdiom
버튼이 눌려졌는가 loadAllItem
서버에서 불러온 아이템 개수 items.count
!
switch (section, currentDeviceIdiom, loadAllItem, items.count)
102. UICollectionView Data Source
패턴매칭으로 리팩토링
충분히 좋아졌지만 case (0, .Phone, false, let count)에서
true/false의 가독성이 좋지 않음
!
switch (section, currentDeviceIdiom, loadAllItem, items.count) 를 보아야
loadAllItem에 대응되는 값이라는 걸 알 수 있음
103. UICollectionView Data Source
패턴매칭으로 리팩토링
loadAllItems는 모다?
위젯을 펼치는 버튼이 눌려졌는지에 대한 조건 값
!
enum TodayWidgetExpandStatus {
case Expanded
case Unexpanded
}
109. Functional
함수형 언어의 “기반”이 있음
!
!
Generic
Closure
Partial 함수
Operator Overloading
Extension
Protocol
110. Protocol
언어의 기본 구성 요소들이 다 Special Protocol을 구현한 것
Objective-C에선 Cocoa/Cocoa Touch 프레임워크에서 프로토콜을 활용
Special Protocol
Printable
“(printable)”
Sequence
for x in sequence
IntegerLiteralConvertible
65536
FloatLiteralConvertible
1.0
StringLiteralConvertible
“abc”
ArrayLiteralConvertible
[ a, b, c ]
DictionaryLiteralConvertible
[ a: x, b: y ]
114. Generic & Protocol
이 스택으로 for .. in을 쓰고 싶다면?
for x in intStack { //컴파일 에러
…
}
!
Swift에서 for x in someSequence 를 쓰면
var __g = someSequence.generate()
while let x = __g.next() {
…
}
120. 언어 확장, DSL
언어를 손쉽게 확장할 수 있는 좋은 기반
그말은 아직은 좀 기본 기능이 부족하다
프로토콜 확장과 오퍼레이터 정의를 통해서 많은걸 할 수 있으나
자신만의 패턴을 만들게 되기 쉽다
확장을 오용하기 쉽다 … (Made by Apple or defacto STL 같은 것을 기대)
!
공부할 것은 많다…
122. Interoperability
Seamless compatibility
모든 Foundation Framework API 사용 가능
NSString, NSArray, NSString, NSDictionary, …
스위프트는 자체적인 String, Array, Dictionary, …
Array와 Dictionary는 제네릭
NS객체들과 스위프트 네이티브 객체는 절대 동일하지 않음, 하지만 브릿징이 가능함
123. String
!= NSString
NSString이 아니다
단 스위프트가 자동으로 NSString과 브릿지를 만듬
NSString이 필요 한곳에 String을 넣으면 알아서 처리됨
NSString을 명시적으로 쓸 일은 거의 없다고… (애플은 주장함)
124. String
=> NSString
스위프트가 Objective-C API를 임포트하면
모든 NSString타입을 String타입으로 암묵적으로 변환
vice versa
137. Gotchas
Objective-C에서 사용
!
!
!
스위프트의 init(dictionary: NSDictionary)가 Objective-C에선 initWithDictionary가 됨
!
그런데 [[ProductOrder alloc] init]을 하고 싶으면?
모든 Objective-C 객체는 init을 지원
138. Gotchas
Objective-C에서 사용
!
!
초기화 되지 않은 객체. 런타임 에러
왜?
OrderBase가 Designated init(dict:NSDictionary)를 만들었기 때문에 NSObject의 init을
상속 받지 않음
그럼 컴파일이 안되어야 하는것 아닌가?
맞음, 그런데 NSObject와의 호환성 문제로 아직 컴파일러가 이를 못잡아내는 듯
148. 그래서 모델 프레임워크를 스위프트로 변환
왜?
스위프트의 Safety가 비UI 부분에 도움이 될거라 생각하였음
차츰 스위프트로 만든 뷰가 많아질거라 예상
….다 필요없고 그냥 하고 싶어서…
149. 그래서 모델 프레임워크를 스위프트로 변환
실수였다…
격주 마다 스위프트 언어 명세가 바뀜. 수백개 이상의 에러
스위프트 파일은 컴파일시 Objective-C 헤더를 만듬
엄청난 양의 자동생성 헤더
컴파일 속도 저하
Swift로 구현한 NSObject 객체를 Objective-C에서 alloc/init
이 객체를 Swift 메소드로 넘김
Swift 메소드에서 업데이트해서 다시 Objective-C로 넘김
Seamless Compatibility!
는 확인했지만 멘탈 모델이 너무 넘나든다…
150. 장점
그래도 좋았던 점은..
코드라인수는 명백하게 줄어듬 (왜냐면 헤더파일을 따로 안만드니까)
패턴매칭은 정말 좋다 (numberOfRows, cellForIndex 등등의 복잡한 조건을 리팩토링)
스위프트 코드내에선 Type Safe (라고 취해본다)
대세를 따라간다 (라고 취해본다)
신규 프로젝트엔 특별히 안 쓸 이유가 없음
151. 도입전략
Swift
새로운 프로젝트에 사용 - OK
기존 Objective-C 프로젝트의 익스텐션에 사용 - OK
기존 Objective-C 프로젝트의 특정 뷰/뷰컨트롤러를 스위프트로 구현 - OK
!
기존 Objective-C 프로젝트를 전부 마이그레이션 ?
기존 Objective-C 프로젝트의 모델을 스위프트로 리팩토링 ?
154. 코드레벨의 도입전략
Swift + NS
현재로는 Objective-C로 작성된 프레임워크/라이브러리의 사용을 피할 수 없음
FoundationKit
AFNetworking
기존의 Extension들
155. 코드레벨의 도입전략
Swift 네이티브 타입에 집착하지 말자
Swift 네이티브 타입 (+ 제네릭)을 쓰면 좋지만
결국 그 코드의 인풋과 아웃풋(UI) 인터페이스는 Objective-C
복잡하거나 의문이 들면 NSString, NSArray, NSDictionary, NSSet등을 사용한다
하지만 이는 컬렉션 단계에서의 타입 안정성을 포기
Javascript로 컴파일되는 Static 언어와 흡사한 형태 (TypeScript, Dart)
156. 코드레벨의 도입전략
네이티브는?
많은 기반 라이브러리들이 NS에 의존하지 않고 스위프트 타입을 지원할 수록 네이티브 자료구조 사
용에 탄력 받을 수 있다
157. Don't Drink the Kool-Aid
약 빨지 말자?
Generic, Protocol, Operator Overloading등을 합치면 언어의 확장이 무척 쉬움
재밌게 공부할 건 많다…
잘못 사용되기도 쉬우며 범용되지 않는 코드 양산
사실상의 표준 역할을 하는 확장들을 기다리는 것도 전략
Ocaml의 Core
C++의 STL
Javascript의 Underscore
158. 도입전략 정리
새로운 앱, 위젯 등은 좋은 선택. 큰 문제 없음
우선 스위프트 네이티브 자료구조에 집착하지 말자
레거시 코드에 도입할 때는 가급적 스위프트에서 Objective-C를 사용하자
반대의 경우는 두번 생각해보자…