Swift3의 NotificationCenter를 지금까지와 가까운 형태로 사용해보기

9618 단어 XcodeiOSSwiftSwift3.0
(추가) 올바른 사용법은 @mono0926
  • Swift 3 이상 NotificationCenter를 올바르게 사용하는 방법

  • 회전 오른쪽.

    ※이하의 내용은 일단 아카이브로서 남겨 둡니다만, 좋은 사용법이 아니기 때문에 양해 바랍니다.



    Swift3.0에서 변경된 NSNotificationCenter



    Swift2에서 Swift3으로 바뀌고, Foundation계에도 손이 가해져 NSNotificationCenter 주위에도 변경이 있었습니다.

    Swift2.2와 Swift3.0에서 addObserve하는 경우의 동일한 처리를 비교해 보겠습니다.

    Swift2
    class Hoge {
        @objc func doSomething(notification: Notification) {
            // ...
        }
    }
    
    NSNotificationCenter.defaultCenter().addObserver(
        self, 
        selector: #selector(hoge.doSomething(_:)), 
        name: "NotificationKey", 
        object: nil
    )
    
    

    Swift3
    class Hoge {
        @objc func doSomething(_ notification: Notification) {
            // ...
        }
    }
    
    let hoge = Hoge()
    NotificationCenter.default.addObserver(
        hoge, 
        selector: #selector(hoge.doSomething(_:)), 
        name: NSNotification.Name("NotificationKey"),  //おや...?
        object: nil
    )
    
    

    여기서 NSNotification.Name 라는 익숙하지 않은 것이 나왔습니다.
    (덧붙여서 Notification.Name 의 것도 있어, 추적하면 NSNotification.Name 의 앨리어스(alias)가 되어 있으므로 거의 동의입니다. 어느쪽으로 써도 실수는 아닐 것.)

    아무래도 Swift3 에서는 통지를 발행하기 위한 nameString 가 아니고 이 NSNotification.Name 를 사용할 수 있게 된 것 같습니다.
    그러나 이것마다
    NSNotification.Name("SomeNotificationKey")
    

    하는 것이 힘들지요.
    그래서, 지금까지 그대로의 형태에 가까운 느낌으로 사용할 수 있도록 해 봅니다.

    마법을 걸다



    가능하면 지금까지와 같이 name: "NotificationKey" 라고 쓰고 싶으므로, NSNotification.Name 에 마법을 겁니다.
    여기서 ExpressibleByStringLiteral 이라는 프로토콜의 차례가 됩니다.
    그건 그렇고,이 ExpressibleByStringLiteral은 Swift2에서 StringLiteralConvertible이라는 이름이었습니다.

    ExpressibleByStringLiteral을 Notification.Name에 적용
    extension NSNotification.Name: ExpressibleByStringLiteral {
        public init(unicodeScalarLiteral value: String) {
            self.init(rawValue: value)
        }
    
        public init(extendedGraphemeClusterLiteral value: String) {
            self.init(rawValue: value)
        }
    
        public init(stringLiteral value: String) {
            self.init(rawValue: value)
        }
    }
    

    이렇게함으로써,
    // good!
    NotificationCenter.default.addObserver(
        hoge, 
        selector: #selector(hoge.doSomething(_:)), 
        name: "NotificationKey", 
        object: nil
    )
    

    이와 같이, 문자 리터럴( "" )를 사용해 지금까지 대로의 쓰는 방법을 할 수 있게 됩니다.

    ... 네, 이것이 변수라면 어떻게합니까? 네요.
    이 경우 변수를 정의하는 형식을 Notification.Name으로 지정합니다.
    
    class Hoge {
        // 左辺側で型を指定してあげることで、右辺はStringではなくて、Notification.Nameと推論される
        static let NotificationKey: NSNotification.Name = "NotificationKey"
    
        // NG : 今までどおりの宣言だと、Stringと推論される
        // static let NotificationKey = "NotificationKey"
    
        @objc func doSomething(_ notification: Notification) {
            // ...
        }
    }
    
    // good!
    NotificationCenter.default.addObserver(
        hoge, 
        selector: #selector(hoge.doSomething(_:)), 
        name: Hoge.NotificationKey,  // 今までどおりいける!
        object: nil
    )
    

    요약



    Swift3가 되어 NSNotification.Name 라든지 나와서 조금 겁났습니다만, 조금 궁리해 주면 취급하기 쉬워질지도 모릅니다. ExpressibleByStringLiteral 감사합니다.



    거기 이용 빈도가 높은, UIApplicationDidBecomeActiveNotification 와 같은 UIApplication 주위의 Notification의 key에 관해서는,
    // swift2まではこれ
    UIApplicationDidBecomeActiveNotification
    // swift3からはこれ
    NSNotification.Name.UIApplicationDidBecomeActive
    

    같이 바뀌었기 때문에 조심합시다. 어쩌면 자동 마이그레이션되어 보완이 효과가 있을지도 모릅니다만. . .
    (처음 어디로 갔는지 알아차리지 않았다...)

    (※ 참고 Xcode8 beta6 시점의 Swift3.0을 기반으로 쓰고 있습니다.

    좋은 웹페이지 즐겨찾기