LoginSignup
47
45

More than 5 years have passed since last update.

XCode7にあげた際のSwift1.2とSwift2の違いメモ

Last updated at Posted at 2015-09-26

はじめに

XCode7で変わった点をまとめます。
といっても、公式なものではなく僕がXcode7にバージョンをあげた時に気づいた事を書いてます。

※Swift2の新しい構文などについては取り上げてません。

Convertvarletまでしてくれる

僕はこの辺はほとんどやってたつもりでしたが、Convertに指摘されました。
なので以下のような構文はConvertが変更してくれます。

func test() {
    var hoge = Hoge()
    hoge.test()
}

上記のように特にhogeインスタンスを変更してない場合は

func test() {
    let hoge = Hoge()   // ←変えてくれる
    hoge.test()
}

このように変更してくれます。

コンパイルが早くなった。

コンパイル速度よりも、それに伴ってコード補完が早くなりました。
僕は古いMacBook Airで開発しているので、これは嬉しい。
ただ、使い続けるとどうなるかはまだ分かりません。

警告が増えた。

今までは使ってない変数があっても警告は出ませんでしたが今回からは警告が出ます。
僕は主に以下のような構文を使ってたのでこれらが警告になりました。

if let foo = hoge as? Foo
    // fooは条件を満たすかどうかのためでしか使ってない。
end

これは以下のように変更しないと警告になります。

if let _ = hoge as? Foo
    // fooは条件を満たすかどうかのためでしか使ってない。
end

また無駄なweakに関しても警告がでます。

CallBlock() { [weak self] in
    // selfを使ってない。
},

コピペコードでありがちな上記なようなコードにも警告を出してくれます。
助かります。

注意点。

僕はgfxさんのSwiftでマルチスレッド時の同期処理はどうやるのかを使用して同期処理をしてましたがこれは警告が発生してます。

class AutoSync {
    let object : AnyObject

    init(_ obj : AnyObject) {
        object = obj
        objc_sync_enter(object)
    }

    deinit {
        objc_sync_exit(object)
    }
}

これを以下のように使っていた。

let lock = AutoSync(self)

警告を解除するために

let _ = AutoSync(self)

とやると、その時点でメモリが解放されてしまいスレッドブロックをしてもらえなくなります。
_weakと同様の扱いのようでretain countを増やしてくれません。)

なので、適当なメソッドを入れて対応しました。

class AutoSync {
    let object : AnyObject

    init(_ obj : AnyObject) {
        object = obj
        objc_sync_enter(object)
    }

    func end() {}

    deinit {
        objc_sync_exit(object)
    }
}
let lock = AutoSync(self)

...何かの処理

lock.end()

警告がでても無視する方はそのまま使ってもいいかと思います。

countやenumerate、containsが自然な形になった。

もともとcountenumerateSwiftクラスが提供してくれてたので

count([])
count("test")

contains(["test", "abc"], "test")   // "test"が配列にあるか?
for (key, value) in enumerate({"key": value}) {
}

という構文で対応してたのですが、以下のように自然な形になりました。
特にcontainsはどっちがどっちだっけと迷うこともあったので助かります。

[].count
"test".characters.count

["test", "abc"].contains("test")    // "test"が配列にあるか?
for (key, value) in {"key": value}.enumerate() {
}

ところでSwiftクラスは無くなったのでしょうか・・・?
あれはオブジェクト指向から逸脱してる特殊クラスだったので廃止されたのかな・・・?

NSMutableDictionary as? [String: AnyObject]ができなくなった。

僕はObjective-cから受け取ったデータを無理やり[String: AnyObject]に変換してました。

let objData:NSMutableDictionary = obj.hash()
let dic = objData as! [String: AnyObject]

しかし、これはもう使えなくなってました。
コンパイルエラーが発生するため素直にNSMutableDictionaryのまま処理をすることにしました・・・。
ただ、Objective-cのNSMutableArrayとNSMutableDictionaryをSwiftで使う際にはまったことNSMutableArrayNSMutableDictionaryのパターンはうまくできました・・・。
この辺りは謎です。

printlnがなくなりました。

これからはprint構文のみになります。

convenience initに?

コンビニエンスイニシャライズが少し変わりました。

required convenience init(coder aDecoder: NSCoder) {
    // 復元処理
}

これが以下のようになります。

required convenience init?(coder aDecoder: NSCoder) {
    // 復元処理
}

test(_ value:int? = nil)が警告に

Swift1.2までは以下のように呼びしたい場合に_が必要でした。

let hoge = Hoge()
hoge.test() // 初期値を与えなくない。
hoge.test(1)    // 初期値を与えたい。

これを行うためには以下の定義をする必要がありました。

func test(_ value:Int? = nil) {
    // _が必要だった。
}

この_がない場合はhoge.test(value: 1)と記載しなければならなかったのですが_はなくてもOKになりました。

親クラスで定義しているプロトコルを子で定義する必要がなくなりました。

今までは親クラスが定義しているクラスも子で定義する必要がありました。

class Parent: NSObject, NSCoding {
}
class Child: Parent, NSCoding {
}

これがコンパイルエラーになり、以下のように子ではいちいち定義しなくても良くなりました。

class Parent: NSObject, NSCoding {
}
class Child: Parent {
}

逆に省略できなくなりました。

今まではメソッドで使わない変数を以下のように省略できました。

func test([Hoge], foo: Foo) {}

これは以下のようになります。

func test(_: [Hoge], foo: Foo) {}

当たり前といえば当たり前ですが、僕はoverrideする時に度々使ってたので今後気をつけます。

Objective-cのメソッドの返却値がOptionalになった気がする。

まだ全部確認が取れてませんが、今までよりもObjective-cの呼び出しが硬くなった気がします。

obj-c.parent.addChild(self)

みたいな構文が以下のようになります。

obj-c.parent!.addChild(self)

第一引数を推測してくれるようになった。

もともとSwiftでは以下の構文でした。

func test(arg1:Int, arg2:Int) {}
test(1, arg2: 2)

このように第一引数の名前は省略できます。
しかし、第一引数が省略可能だった場合は名前の省略ができませんでした。

func test(arg1:Int = 0, arg2:Int = 0) {}
test(arg1: 1, arg2: 2)      // arg1が省略できない。

Swift2からは上記の場合でも第一引数の省略ができます。(というかしないとコンパイルエラーになります。)

func test(arg1:Int = 0, arg2:Int = 0) {}
test(1, arg2: 2)        // arg1は不要

複雑な構文がNGになりました。

複雑な構文をブロック内に記載するとコンパイルエラーになるようになりました。

CallBack = {
    $0.items.filter{ $0.type == .A || $0.type == .B }.count
}

このような構文を書くと以下のエラーが発生します。

Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

これは以下のように記載します。

CallBack = {
    let items = $0.items.filter{ $0.type == .A || $0.type == .B }
    return items.count
}

ブロック内で2行以上に渡る場合はreturnが必須なのでお忘れなく。

Enumのswitch#defaultに警告が出ます。

今までは以下の構文でも警告が出ませんでした。

enum HogeType {
    case A
    case B
}

switch {
case A:
    // 何かの処理
case B:
    // 何かの処理
default:
    // 何かの処理
}

僕は後々増える予定のEnumをdefaultで拾う予定のコードを書いてたのですが、これは警告が出ます。
普通に使う場合はとても良い変更です。

String#toInt()が廃止に

今までは文字列をInt型に変換する時に以下のように行ってました。

let intValue = "1".toInt()!

これは廃止され

let intValue = Int("1")!

になりました。
Int()がOptional型で返却されるというのに注目です。
(これが自然かどうか微妙ですが。convenience init?がつくようになったため可能になったのでしょう。きっと。※実装を見てもそんなコードは見当たりませんでしたが・・・どうやってるのかな?)

CFBundleIdentifierが$(PRODUCT_BUNDLE_IDENTIFIER)に

info.plistのCFBundleIdentifier$(PRODUCT_BUNDLE_IDENTIFIER)が適用されます。
僕に対したメリットがないですが、、、

ただ、この変更のためかXCode7対応時にCFBundleIdentifierが消えてしまうという謎の障害に頭を悩ましました。
もし以下のエラーが出た場合は上部にあるBundleIdentifierが正しいか見てみましょう。

スクリーンショット

愚かにも僕はこれで相当手こずりました・・・。

iOS7のシミュレーターがなくなりました。

僕のような個人アプリを作ってる人は良いですが、企業でやってる人は注意してください。
XCode7からはiOS7のシミュレーターがなくなってるので実機でしかテストができないです。

ただ、実機テストが無料になったので端末さえあればそんなに問題にはならないと思います。

Pod Installが必要の場合も

僕の場合はcocoaPodの古いバージョンを使ってたためPod周りでエラーが出ました。

$ bundle exec gem install cocoapods

podを最新にして

$ pod install

をすれば解決します。

まとめ

警告が増えたのはとても良かったです。
僕は結構硬いコードを書いてたつもりだったのですが、いくつか引っかかってしまったので助かりました。

また、コンパイル速度が上がったのも良い変更です。
XCode7にあげるのはなかなか苦痛を伴いますが、これからSwift2を楽しめるのであげて良かったかなと思います。

あとコンバータが結構優秀で助かりました。
なにも見ずにsaveしても多分問題は発生しません。(Swift1.2の時はそれなりにエラーが発生してた・・・)

おまけ

僕はcocos2dで作ったプログラムだったので、XCode7にあげた時に結構きっつい対応が必要でした。
とにかくエラーの原因がわからず最後の最後まで以下のエラーに悩まされました。

object file (/libcocos2d.a(OALSimpleAudio.o)) was built for newer iOS version (9.0) than being linked (7.0)

この手のワーニングはもう諦めました・・・

あと、プログラムは動くけれどエラーが出るという現象も発生しました。
こちらに解決策が書かれてましたが、metallibを作らないわけなので抜本的な解決策ではありません。。。
僕はmetalを使ってないので問題ないのですが、metalを使ってる人は注意が必要です。

gitを使ってからやる方が良いです。

忘れてました。
XCode7にあげる前に必ずgitへコミットしておきましょう!

いざという時に戻せる安心感と、プロジェクトファイルとかが勝手に書き換えられた場合の差分を見たりできます。
僕はgitにも随分助けられました。

では、Swift2を楽しんできます。

47
45
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
45