Xcode9になって、Swift4が使えるようになりました。
Swift3で書かれたプロジェクトを開くと、Swift4への変換のメッセージがでます。
なんだかframeworkやCocoaPodsも巻き込んでいきそうな感じです。以前のSwiftのアップデート時には、派手にソースが変更されて冷や汗をかきました。
今回ももしやと、びくびくしながら続けていくと、大した変更はありませんでした。
変換された部分は、#selector()で指定しているイベントのアクションの関数の定義に、@objcが付けられた程度です。
//略
let nc = NotificationCenter.default
nc.addObserver(self,
selector: #selector(Foo.bar),
name: "piyo"
object: nil)
//略
@objc func bar() {
//略
}
//略
しかし、なぜ@objcなんでしょうか。このプロジェクトはすべてSwiftで書かれていますし、何だか腑に落ちないです。どこから来たのobjc属性。
しかも追加された@objcの箇所にワーニングが出力されます。何か間違ってませんか?
Selector Expression
A selector expression lets you access the selector used to refer to a method or to a property’s getter or setter in Objective-C.
#selector(method name)
#selector(getter: property name)
#selector(setter: property name)
The method name and property name must be a reference to a method or a property that is available in the Objective-C runtime. The value of a selector expression is an instance of the Selector type.
(“The Swift Programming Language (Swift 3.1)”/Apple Inc.より)
ふむふむ。
セレクタはObjective-Cの概念であるため、Selector型を生成するにはメソッドがObjective-Cから参照可能である必要があります。メソッドをObjective-Cから参照可能にするには、objc属性を指定します。
(Swift実践入門/石川洋資,西山勇世 P289より)
なるほど。
どこかからObjctive-Cが湧いてきたわけではなく、そもそもセレクタはObjecive-Cのランタイムにおける概念なのですね。
これはSwift4の書式に変換してくれたというより、本来必要だった@objcを、厳しくなったコンパイラのために付けてくれたということなのでしょう。
試しに、@objcを削除してみるとエラーになります。
Argument of '#selector' refers to instance method 'bar()' that is not exposed to Objective-C
Add '@objc' to expose this instance method to Objective-C
ちなみに、objc属性の箇所のワーニングですが、
The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the "Swift 3 @objc Inference" build setting to "Default" for the "xxxxxx" target.
これは、TARGETSのBuild Settingsをswiftで検索して、Swift 3 @objc Inference(Onになっていると思います)を、Defaultにすると消えます。
これで安心してSwift4を使えますね。