[Swift] Xcode6.3に上げたらビルドが通らなかった話

Xcodeが6.3にバージョンアップし、激遅だったSwiftのコンパイルが速くなったそうですが、Xcode6.2以前のプロジェクトを持ってくると大量のエラーが出てしまいます。。。

Swiftは1.2へ

Swiftは、Xcode6.0リリース時にSwift1.0として公開され、Xcode6.1でSwift1.1へ、そして最新のXcode6.3ではSwift1.2となりました。

1.0と1.1でさほど変更点はありませんでしが、1.2では記述が変わったものが幾らかあり、そのままではコンパイルすることが出来ない可能性が高いです。

そのようなことからからXcode6.3では、古いSwiftのソースコードをSwift1.2仕様にコンバートしてくれる機能がついています。

メニューの [Edit] > [Convert] > [To Latest Swift Syntax…]で表示される画面で[Next]を押すと、ターゲットの一覧が表示されるので、アプリのターゲットのみチェックをし、コンバートを行います。

コンバートする箇所の検索が終わると一覧で表示されるので、内容を確認し[Save]でコンバート完了です。

Swift1.2の仕様変更でコンパイルが失敗する箇所

ダウンキャストは、as!を使う

Swift1.2で一番大きは影響を受けるのは、ダウンキャストの仕様変更です。

以前は、AnyObjectをStringやIntにキャストする時に、

キャスト出来るのが明らかな場合は、

let object: AnyObject = "text"

let string = object as String

というようにasでダウンキャストを行っていましたが、1.2ではas!とする必要があります。

キャストに失敗する可能性があれば、以前と同じようにas?することでオプショナルの値にキャストすることができます。

let object: AnyObject = "text"

let string = object as! String // "text"

let optionalString = object as? String // Optional("text")

let integer = object as? Int   // nil

countElements()の廃止

次に大きく影響しそうなのが、countElements()の廃止です。

Swift1.2では、文字数を数えるのにcountElements()ではなくcount()を使います。

ちなみに、1.1でもcount()という関数があり、countElements()と同じであると定義されています。

インスタンスのlet定数への代入は、初期値を含め1度のみ

let定数は、基本的に生成時に一度値を入れることしか出来ませんでしたが、クラスや構造体などのlet定数については、定義時に初期値を設定し、初期化時にも値を設定できました。

class Human {
    let firstName: String = "Taro"
    let lastName: String  = "Tanaka" 

    init(name: String) {
        let names = name.componentsSeparatedByString(" ")
        if names.count == 2 {
            self.firstName = names[0]   // 1.1まではここで値を設定できたが
            self.lastName  = names[1]   // 1.2からは設定出来ない
        }
    }
}

1.2からは、let定数をイニシャライズで初期化する場合は、定義する際に初期値を設定することが出来なくなりました。

class Human {
    let firstName: String
    let lastName: String

    init(name: String) {
        let names = name.componentsSeparatedByString(" ")
        if names.count == 2 {
            self.firstName = names[0]
            self.lastName  = names[1]
        } else {
            self.firstName = "Taro"     // 初期化は必須
            self.lastName  = "Tanaka"
        }
    }
}

NSStringの値をStringとして扱う場合は、キャストが必要

NSStringの変数を、Stringの変数に代入する場合などは as Stringでキャストする必要があります。

また、StringからNSStringへの代入時は、キャストの必要がありません。

var nsstring = NSString(string: "text")

let string: String = nsstring as String // ここだけ必要

nsstring = string

 

Swift1.2への移行はお早めに

Xcodeのコンバート機能が優秀で、すぐにビルド出来るようになるとは思いますが、コンパイラがより厳密になったのか、以前は通っていた曖昧な書き方がNGになっていることもあり、手動で修正する必要があったりもします。

Xcode6.3+Swift1.2では、ビルド速度が向上し、補完が効かなくなることもある程度減っている感じですので、出来るだけ早い移行を検討したほうがよさそうです。

この記事を書いた人

タケシ
タケシ
プライベートは趣味で忙しいLegend先輩 アプリチームではヒカセンの加入をお待ちしております
Pocket