iOS8が発表され、Swiftが解禁されてからしばらく経ちました。
iOSをやり始めて勉強用に作ったマイQiitaをまるっとSwiftに移植してみました。
Swiftが発表されてすぐに色々いじっていましたが、実際にアプリとして書き始めてみると気づく点もたくさんありました。
今回は色々ハマったり気づいた点をまとめていこうと思います。
ProductName-Swift.h
は、ObjC側では.m
にimport
する
これ、少しハマりました。どうやらヘッダファイルでimportするとダメなようです。
Swiftで定義したenumはObjC側で使えない
Swiftでenumが大幅に強化されました。
それもあって、Swift側で定義したenumはObjCでは使えないようです。
Optionalをしっかり意識する
Swiftの重要な概念である「Optional」ですが、しっかりと意識していないと細かいところでハマりました。
というのも、なにがしかのメソッドの戻り値だったり、あるいはFrameworkのプロパティをローカル変数に代入しようとしてエラーになることがあります。
これは単純にOptionalな型なのに、Optionalな型ではない変数に入れようとするためです。
が、ObjCを移植したりしているとついコードをコピペしてSwiftの見た目に整える、みたいなことをやるので忘れがちです。
さらにXcodeの成熟度の問題か、指摘されているのが適切ではかったりするのでさらに混乱しました。
ビルドエラーになるとProductName-Swift.h
が消える
SwiftのクラスをObjC側で利用する仕組みとしてブリッジファイルの存在があります。
Swift → ObjCの場合はXcodeが自動生成してくれるので特に意識する必要はありません。
が、Swift内でビルドエラーがあるとファイルが消されてしまうようで、ObjC側でそれをimportしている部分でさらにエラーが発生します。(消えずにいるが、ビルド時に一度消えてる? あるのにnot foundになるケースも)
問題はSwift側なのでObjC側をいくらいじっても解決しません。
なので、まずはSwift側を修正してから再度試してみると普通にビルドできたりします。
self
と self.class
と self.dynamicType
ObjCでは、インスタンスメソッド内からクラス・メソッドを呼ぶ場合に、[self.class someMethod]
と記述していました。
Swiftの場合は以下のようにdynamicType
を使うことで同様のことが出来ます。
class Hoge {
var name: String?
class func classMethod() {
print("hoge")
}
func instanceMethod() {
self.dynamicType.classMethod()
}
}
NSOrderedAscendingなどのenum値でハマる
結論から言うと、以下のようにしました。
var result: NSComparisonResult = hoge.compare(comparedNumber)
if result == .OrderedAscending {
// do something.
}
名称が微妙に推測しづらいものだったので一瞬悩みました。
CoreDataのcontext.executeFetchRequestでハマる
最初、以下のよう記述しました。
var results: [Hoge] = context.executeFetchRequest(request, error:&error)! as [Hoge]
見る限り普通のコードですね。
が、しかし。
fatal error: NSArray element failed to match the Swift Array Element type
とエラーが。castしてるしなんだよーと思っていたら、まったく同じ質問をStackoverflowでしている人がいました。
そこで記載されている画像を引用させてもらうと以下の感じです。
要は、CoreDataのモデルの設定を上記のようにすることで正常に動くようになります。
Swiftはnamespaceがあるので、情報としてそれらを含めた正確な情報を指定しないとならないようです。