Swift3とObjective-Cのブ
リッジでハマったこと
@yousan
集まれSwift好き!Swift愛好会 Vol12
自己紹介
• @yousan
• iOSアプリエンジニア
• 趣味 テニス
Swift3移行中
Objective-Cでクラッシュ
let person = Person(nickname: "yousan")
let uppercaseNickname = ObjCUtils.convert(toUppercase: person.nickname)
print(uppercaseNickname)
@implementation ObjCUtils
+ (nonnull id)convertToUppercase:(nonnull id)string {
return [string uppercaseString];
}
@end
Swift
Objective-C
Terminating app due to uncaught exception 'NSInvalidArgumentException
let person = Person(nickname: "yousan")
let uppercaseNickname = ObjCUtils.convert(toUppercase: person.nickname)
print(uppercaseNickname)
@implementation ObjCUtils
+ (nonnull id)convertToUppercase:(nonnull id)string {
return [string uppercaseString];
}
@end
Swift
Objective-C
struct Person {
let nickname: String?
}
オプショナルでした
Swift2のときはAnyObjectだったので
コンパイル時にエラーになっていた
id → Anyの注意
+ (nonnull id)convertToUppercase:(nonnull id)string;
class func convert(toUppercase string: Any) -> Any
class func convertToUppercase(string: AnyObject) -> AnyObject
Swift2
Swift3
オプショナルは引数に渡せない
オプショナルも引数に渡せる
Objective-C
nonnullでもコンパイルエラーにならない
idである必要がなければ型を指定
+ (nonnull NSString *)convertToUppercase:(nonnull NSString *)string;
class func convert(toUppercase string: String) -> String
Objective-C
Swift3
NSArray, NSDictionary, NSSetはジェネリクスを指定
+ (nonnull NSArray<NSString *>)convertToUppercase:(nonnull NSArray<NSString *>)strings;
class func convert(toUppercase strings: [String]) -> [String]
Objective-C
Swift3
外部ライブラリは気をつけるしかない
なぜこんな改変を?
• SE-0116
https://github.com/apple/swift-evolution/blob/master/proposals/0116-id-as-any.md
• Objective-C id as Swift Any - Swift Blog
https://developer.apple.com/swift/blog/?id=39
• 5分でわかるSE-0116(id-as-any) // Speaker Deck
https://speakerdeck.com/takasek/5fen-dewakaruse-0116-id-as-any
Swift2
// StringがAnyObjectに暗黙的に変換されている
let converted = ObjCUtils.convertToUppercase("yousan")
書きやすいように暗黙的にAnyObjectに変換している
本来関係のない型に、しかも暗黙的に変換されるのは
色々な問題を生むのではないか?
Swift3
let name: AnyObject = "yousan" as AnyObject // AnyObjectへの変換を明示
let converted = ObjCUtils.convert(toUppercase: name)
let uppercaseNickname: String = converted as! String
print(uppercaseNickname)
該当する場所全てにこれを書くのは大変
SE-0072
Fully eliminate implicit bridging conversions from Swift
AnyObjectをAnyにすれば
• AnyObjectへの暗黙変換は発生しない
• AnyObjectへの変換処理も書く必要がない
• 全てのSwiftの型をObjective-Cに渡せる
※ 渡した結果どうなるかはコンパイラに任せる
将来的には全てのSwiftの型をブリッジしたい
Objective-Cに対応する型がな
い場合どうなるか
• _SwiftValueというクラスとして受け取る
• 今後もObjective-Cに対応づけられるSwiftの型は
増えていくので、この型に依存するべきではな
い
例えば
https://github.com/apple/swift-evolution/blob/master/proposals/0139-bridge-nsnumber-a
• Int16 → _SwiftValue
• CGRect → _SwiftValue
Swift 3.0.1
• Int16 → NSNumber
• CGRect → NSValue
Swift 3.0
まとめ
• Objective-Cでidに値を渡すときはオプショナル
に注意
• Objective-Cに渡せるSwiftの型は今後も増えてい
くと思われます

Swift3とObjective-Cのブリッジでハマったこと