IT/IPhone개발

[Swift] xcode 7.3 Swift 2.2 변경된 것들

차가운남자 2016. 4. 27. 11:42

1달전인가? 2016.3월 중순쯤에 xcode 업데이트가 되면서 swift 2.2 버전으로 릴리즈 되었던것 같습니다

스위프트 스터디중 기존 예제 및 동영상 소스들을 적용하는데 error 또는 warning이 발생이 발생되어서 사이트를 돌아다니다 정리가 잘된것이 있어서 공유합니다.


좀 더 완벽하게 실패(?)하는 생성자

개인적으로 가장 환영하는 변화점이다. 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)에 좀 더 자유로운 이름을 쓸 수 있게 되었다. 예를 들어 특정 용도로 쓰이는 inoutlet,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 구문으로 변경하자.


'IT > IPhone개발' 카테고리의 다른 글

[Swift] Segue로 값넘기기  (0) 2016.05.03
[Swift] UIAlertView 바뀐 사용법  (0) 2016.05.02
[swift] 공부하기 괜찮은 사이트  (0) 2016.04.26
[Swift] TableView 파해치기  (0) 2016.04.22
UITableView custom cell 가지고 놀기  (0) 2016.04.20