Swift 2.2 에선 뭐가 바뀌었나
Xcode 7.3과 함께 Swift 2.2도 함께 정식으로 릴리즈 되었다. 요즘엔 공식사이트도 생기고 오픈소스화 되면서 변경 내역을 접하기가 쉬워지고 정리도 잘 되어 있어서 이런 글을 적는게 의미가 있나 고민되기는 하지만, 그래도 복습하는 겸 정리해본다.
여기서는 언어의 변화만을 개인적인 선호(?)도로 필터링하여 정리하려 한다. Xcode 7.3 의 변경내역은 직접 읽어보자.
하지만 Swift 2.2 부터는 이제 문제 없이 컴파일되고 의도대로 동작한다. 사실 이게 맞고 이전의 요상한 에러가 도저히 이해할 수가 없었는데 이제서야 바로잡혔다. 실패가능한 클래스 생성자가 실패해서 nil 을 리턴하는데 굳이 멤버 프로퍼티들을 만들어 줘야 할 이유가 없으니깐.
비슷하게
사실 디버깅 측면을 제외하곤 크게 쓸 일이 없는 키워드라서 모르는 분들도 많을 것 같다. ' ~ '
약간 다른 예제를 보자.
이 글의 내용은 내 이해도를 바탕으로 쓰여졌기 때문에 잘못된 내용이 있을 수 있다. 이걸 감안하고 제대로 이해하고 싶다면 원문을 반드시 읽어보자.
[관련글] 스위프트(Swift) 가이드
[관련글] Swift 오픈소스화 소식과 미래의 이야기들
여기서는 언어의 변화만을 개인적인 선호(?)도로 필터링하여 정리하려 한다. Xcode 7.3 의 변경내역은 직접 읽어보자.
좀 더 완벽하게 실패(?)하는 생성자
개인적으로 가장 환영하는 변화점이다. Failable Initializer(init?)나 예외를 던지는(throw) 생성자(init)가 이제return nil
을 할 때의 속박에서 벗어나게 되었다. 뭔 말이냐 하면 아래 예제를 보자.
class SomeClass { let value: Int init?(customValue: Int?) { guard let customValue = customValue else { return nil } self.value = customValue } }위 코드는 Swift 2.2 미만에서는 컴파일 에러가 발생한다. 왜냐하면 nil을 리턴하는 시점에 프로퍼티 초기화를 모두 하지 않았기 때문이다.
하지만 Swift 2.2 부터는 이제 문제 없이 컴파일되고 의도대로 동작한다. 사실 이게 맞고 이전의 요상한 에러가 도저히 이해할 수가 없었는데 이제서야 바로잡혔다. 실패가능한 클래스 생성자가 실패해서 nil 을 리턴하는데 굳이 멤버 프로퍼티들을 만들어 줘야 할 이유가 없으니깐.
비슷하게
super.init()
를 호출하는 경우나 예외를 발생시키는 경우(throw)도 이제는 모든 프로퍼티 초기화를 하지 않고도 가능해져서 한결 편리한 코딩이 가능해졌다.컴파일 타임 버전 확인
전처리기(Preprocessor) 스타일 문법으로 Swift 언어의 버전을 확인할 수 있게 되었다. 그냥 아래 예제면 이해가 가능할 것 같다.#if swift(>=2.2) print(“Hello!”) #elseif swift(1.0) println(“Hello!”) #else This code will not parse or emit diagnostics #endif
자유로워진(?) 필드 이름표
함수 인자 이름표(label)에 좀 더 자유로운 이름을 쓸 수 있게 되었다. 예를 들어 특정 용도로 쓰이는inout
, let
, var
같은 키워드 말이다. 다만 앞의 키워드들은 인자쪽 선언에 쓰이는거라 그냥 쓸 수는 없고 아래 예제처럼 백쿼트로 묶어줘야 한다.
func something(`in`: Int, `inout`: Int) -> Int { return `in` + `inout` } let result = something(1, `inout`: 2)개인적인 감상은 이런짓 하지 말자이다. 괜히 헷갈리는 키워드 넣을 이유도 없고 괜히 고생스럽고 읽기도 힘든 백쿼트를 넣어야 할 설득력이 부족할 것 같다. 백쿼트 없이 되는 키워드만 쓰는게 좋을거라 생각한다. 물론 개인적인 견해일 뿐이다. ' ~ '
튜플 비교
튜플(Tuple)의 비교연산자가 추가되었다... 라는 말 보다는 그냥 튜플끼리의 비교가 가능하게 되었다라고 하는 편이 좋을 것 같다.(1, 2, 3) == (1, 2, 3) // true (3, 1, 2) == (1, 2, 3) // false물론 튜플 아이템 타입이 Comparable 을 만족하는 타입일 경우에만 가능하다.
추가된 전처리기
기존 방식으로 로그를 찍어왔다면 알 수 있을지도 모르겠다. 현재 파일이나 함수, 라인수 등을 로깅할 때 쓰이던__FILE__
, __LINE__
, __COLUMN__
, __FUNCTION__ 키워드가 전처리기 스타일로 바뀐다. 각각 #file
, #line
, #column
, #function
으로 바뀐다. 이 코드들을 쓰고 있다면 미리 수정해 두자.사실 디버깅 측면을 제외하곤 크게 쓸 일이 없는 키워드라서 모르는 분들도 많을 것 같다. ' ~ '
셀렉터 문법
아직도 벗어날 수 없는 Objective-C의 함정, 셀렉터(selector) 표현 문법이 변경되었다. 기존의 경우 문자열 형태로 써야해서 컴파일 단계에서 오류를 확인 할 수가 없었는데 이제 네이티브 문법으로 표현할 수 있게 되었다.class MyNotifyClass { init() { let sel = #selector(self.mySelector(_:)) NSNotificationCenter.defaultCenter() .addObserver( self, selector: sel, name: "Foo Bar", object: nil) } @objc func mySelector(id: AnyObject) { // ... } }물론 여전히 Objective-C 셀렉터 호환성을 위해
@objc
를 붙여야 한다. 아직도 Objective-C 의 잔재를 피할 수 없다. 물론 NSObject를 상속받는 방법도 있는데 이건 더 심한거니...함수 별명 짓기
앞서 본 셀렉터와 비슷한 개념으로 생각 할 수도 있고, 다르게 보면 C의 함수포인터와도 비슷하게 생각할 수도 있는 기능이다. 일단 아래 예제를 보자.let date: () -> NSDate = NSDate.init let timestamp = NSDate.init(timeIntervalSince1970:) date() // NSDate() 가 호출된다 timestamp(timeIntervalSince1970: 2000.0) // NSDate(timeIntervalSince1970: 2000.0) 가 호출된다date와 timestamp라는 변수를 마치 함수처럼 이용하고 있다. date는 NSDate의 별칭으로, timestamp는 NSDate의 1970년 이후의 초단위 시간을 이용하는 생성자의 별칭으로써 동작한다. 동일한 클래스지만 라벨을 이용해 다른 생성자를 호출 할 수 있다는 것을 알 수 있다.
약간 다른 예제를 보자.
class MyClass { var value: Int = 0 func increase(step: Int) { value += step } @objc func decrease(step: Int) { value -= step } } let obj = MyClass() let inc = obj.increase let dec = obj.decrease obj.value // 0 inc(1) obj.value // 1 inc(20) obj.value // 21 dec(5) obj.value // 16이번엔 커스텀 클래스의 메소드에도 별칭을 붙이는 방식을 이용했다. 이런 방식도 가능하다는 것을 보여주기 위해 만든 억지(?) 예제라고 생각하자. 좀 더 자세한 건 SE-0021를 참고하자.
associatedtype
연관타입에 한해서 typealias 대신 associatedtype 키워드를 사용해야 되도록 바뀌었다. 일단 typealias가 사라지는건 아닌 것 같고 protocol 이나 extension 등에서 typealias를 이용해 내부에서만 사용되는 타입의 별칭을 지을 때 typealias 대신 associatedtype 이라는 이름을 쓰도록 강제하는 것 같다.protocol SomeType { associatedtype ValueType: SequenceType func someMethod(value: ValueType) } struct Some: SomeType { func someMethod(value: [Int]) { // ... } }기능적으로 달라지는 것 같지는 않아보이기 때문에 가독성 측면에서 잇점을 가지게 하기 위함으로 보인다.
사라져 가는 것들(Deprecated)
Swift 3.0 을 대비해서 사라질 것 같은 문법들이 있다. 즉 아직은 쓸 수 있다는 말이다. 하지만 미래를 대비해서 deprecated 경고가 뜨는 문법은 미리 수정해 두자. 참고로 많은 부분은 이미 이전에 글을 써 두었기 때문에 간략하게만 언급한다.- 커리드 함수(Curried Function): 기존에 알려진 대로 클로져로 대체하자.
++
,--
: 이것도 모호성을 만들어 내는 요소인 만큼 사라질 문법이다. 이제는+=
스타일의 문법을 쓰자.anyGenerator()
: 이제는 AnyGenerator 라는 프로토콜을 따라야 하는 것 같다.Selector
: Selector()를 이용해 문자열로 셀레터를 만드는 문법이 사라질 예정이다.#selector()
를 이용하자.- C Style for loop: 이제 for x;y;z 구문 대신 for in 구문으로 변경하자.
마무리
이 외에도 Swift 2.2의 변경 사항은 많다. 그 중에는 특히 Swift 3.0 으로 가는 과도기적인 변화도 많다는 점을 주목하자. 개인적으론 Swift 3 부터가 진정한 시작이 아닐까 생각될 정도로 2.2의 변화는 크다고 느껴질 정도다.이 글의 내용은 내 이해도를 바탕으로 쓰여졌기 때문에 잘못된 내용이 있을 수 있다. 이걸 감안하고 제대로 이해하고 싶다면 원문을 반드시 읽어보자.
[관련글] 스위프트(Swift) 가이드
[관련글] Swift 오픈소스화 소식과 미래의 이야기들
댓글