euphonictechnologies’s diary

Haskell超初心者の日記です。OCamlが好きです。

follow us in feedly

Swift 1.2から2.2でウラシマ状態 - ワーニングを撲滅する

ワーニングはエラーだ

今更かも知れませんがワーニングはエラーです。ワーニングはエラーです。ワーニングはエラーなんです。ワーニングを放置してコミットする意味がわかりません。なのでワーニングを修正していきます。

f:id:euphonictechnologies:20160605145205p:plain

このエントリは前回のエントリの続きです。

blog.euphonictech.com

ワーニングたち

Variable 'nantoka' was never mutated; consider changing to 'let' constant

これは非常にいいワーニングですね。varだけど一度しか代入されていないものはletじゃねえの?っていういいおせっかいです。Fix-itがあるのでクリックしちゃいましょう。たぶん賢いSwiftコンパイラのことなのでletだろうがvarだろうが変化するかしないかをきちんと解析して最適化をかけてくれると思うので、仕上がりのバイナリにそれほど違いは出ないと思うのですが、letにしておけばSwiftコンパイラは安心して定数としての最適化をかけることができます。

それにもましてconstを増やせば増やすほどコードは頑丈になります。letしましょう。

Forced cast of '[UIWindow]' to same type has no effect

let windows = UIApplication.sharedApplication().windows as! [UIWindow]

こういうの、返り値の方がちゃんと直っているみたいです。昔はNSなんとかが返っていたんでしょう。素直にFix-itで消しちゃいましょう。

今気づいたんですが、左っ側のワーニングとエラーの一覧のペインのエントリをクリックするとその場所にジャンプするだけじゃなくてFix-itが使えるときはFix-itの内容を表示してエンターするだけで治るようになってますね。たくさん修正するときにクリックエンターの繰り返しで簡単にできるようになっていてとてもよいです。一気に直すみたいなのもあるといいなと思いましたが、一個一個一応見ようぜというAppleの心遣いなんでしょうか。

f:id:euphonictechnologies:20160605143418p:plain

Treating a forced downcast to '[String: AnyObject]' as optional will never produce 'nil'

let titleDict: NSDictionary = [NSForegroundColorAttributeName: colorPalette.uiColorText]
UINavigationBar.appearance().titleTextAttributes = titleDict as! [String : AnyObject]

これ実は前回のエントリでas!に直したものだと思います。これ、NSDictionaryを普通の辞書に直しているからおかしなことになっているので、NSDictionaryを普通の辞書に直します。

let titleDict: [String : AnyObject] = [NSForegroundColorAttributeName: colorPalette.uiColorText]
UINavigationBar.appearance().titleTextAttributes = titleDict

こうですね。変なボクシングとアンボクシングが必要になりました。Swit2.2たしかに前よりいいね。

Use of string literal for Objective-C selector is deprecated; use '#selector' instead

SegmentTableCell(tableView: self.tableView, id: "blackPlayerSegment", labelText: "Black player", segmentItems: ["Human", "Computer"], selectedSegmentIndex: blackSSI, targetObject: self, targetSelector: "changeSegmentBlackPlayer:"),

こういうやつです。ここでtargetSelector: "changeSegmentBlackPlayer:"がだめらしい。この"changeSegmentBlackPlayer:"Objective-Cのメッセージパッシング原理主義的オブジェクト指向では許されていたやつですね。当然コンパイル時に全くチェックができないのでここをコンパイラがチェックできる形式にする…ということかな? ここで不正なセレクタを指定すると

f:id:euphonictechnologies:20160605144302p:plain

となります。だめみたいですね。

'++' is deprecated; it will be removed in Swift 3

インクリメント演算子はなくなると。残念です。a += 1みたいに書けということらしいです。なんの利点があるんでしょうか。とはいえ私はインクリメント演算子はあんまり好きじゃないです。というのもa += 1と書いたほうが代入文だということがわかりやすいからです。そりゃそうだろ、と言われるかもしれませんが、そりゃそうです。「インクリメント演算子の便利さはfor文とか関数の引数としてとかあんだろ」と言われるかもしれません。例えばCで例を出すと

/* C */
q = f(i++);

みたいな感じで一行にまとめられます。便利ですね。でも

/* C */
q = f(i++) + g(++i);

ってどうなんでしょう。これはおんなじSequence point内でiに対する変更と読み取りが両方発生するのでコンパイラワーニングになります。でもってその結果はコンパイラの作者次第です。てことはおんなじ行内でこういうことできないんだから明示的にした方がいいよねってなるとa += 1として独立した行に書くのがいいのかもしれません。当然(a+=1)として置き換えてその場でインクリメントしてそのまま使うこともできますが、流石にそんな気持ち悪いのは書かねえだろってこと・・・でしょうか。

/* C */
q = f(i) + g(i+=1);
i+=1;

やっぱちょっときもいですもんね。

さらに、Swiftは演算子オーバーロードがあるので

var q = f(i++) + g(++j)

これは大丈夫でしょうか。このコードだけではわかりません。やっぱりSequence pointを大事にする姿勢からするとインクリメント演算子はとりあえずなくしてきれいに書く癖を強制させる方向性なのかな、ということをインクリメント演算子の将来的な削除から考えました。結論:どっちでもいい!

メイヤー先生はいらないと考えているみたいですね。

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

オブジェクト指向入門 第2版 原則・コンセプト (IT Architect’Archive クラシックモダン・コンピューティング)

C style for statement is deprecated and will be removed in a future version of Swift

for var by : CGFloat = 0; by <= width; by += piece_width {
...

って感じのやつです。Pythonみたいに書くのがいいというわけですね。つまり

for i in 0..<5 {
}

みたいな書き方ですね。ただこれ、増分1固定なので僕のオリジナルの文は書き直せません。ここでstrideを使います。

for i in stride(from: 0, through: width: by: piece_width) {
}

とすると上と同じになります。

stride(from: 0, to: 1, by: 0.2)            // 0.0, 0.2, 0.4, 0.6, 0.8
stride(from: 0, through: 1, by: 0.2)  // 0.0, 0.2, 0.4, 0.6, 0.8, 1.0

という違いがあります。ここにはStrideableなる新しい型の作用があるみたいですね。参考:

Swift: Six Killer Features — Erica Sadun

Strideable Protocol Reference

swift-evolution/0007-remove-c-style-for-loops.md at master · apple/swift-evolution · GitHub

Immutable value 'nantoka' was never used; consider replacing with '_' or removing it

これは使われてない変数の取り扱いに関する警告ですね。消せるところは消しちゃいましょう。forの条件に使われていたりする場合は_に置き換えちゃいましょう。

        for _ in 0..<height {
            var row: [Double] = []
            for _ in 0..<width {
                row += [initVal]
            }
            self.zones += [row]
        }

ちなみにこうやっても上と下の_は混じりませんよ。安心してください。

'var' parameters are deprecated and will be removed in Swift 3

func sum (var array : [Int]) {

これ、変数は基本constで、変更する場合はvarをつけなければいけませんでした。これはそのうちinoutに置き換わる予定です。こうやってimmutablityを重視するのって本当にいいですね。

Result of call to non-mutating function 'sort' is unused; use 'sortInPlace' to mutate in-place

これはワーニングの中でも特に重要に思います。以前はsort関数はsequenceの中身を直接変更するものでしたが、これからはそのsortしたものを返す関数になっているようです。

        arr.sort({
            $0.0 > $1.0
        })

とかやると何にもしない文になります。sortInPlaceしましょう、というよりarr = art.sort~と書き直したほうが良いように思います。RValue optimizationがかかる…のかな?そうだといいな。

プロジェクトの設定のワーニング

こんな感じのものが出ました。

f:id:euphonictechnologies:20160605153758p:plain

面倒なんでPerform Changesしちゃいましょう。

一応調べてみると

  • Turn on "Enable Testability" When Debugging

この"Enable Testability"はテストクラスの冒頭で

@testable import ClassToBeTested

するだけで大丈夫になるみたいです。便利ですね。

  • Disable Safety

これは-Ouncheckedフラグの代わりみたいです。私のような完璧無敵超人に配列の境界チェックは必要ないのでuncheckedにしているのですが、Disable Safetyで置き換えみたいです。

綺麗になりました

ワーニングは全部修正できたみたいです。というわけで、次はSwift1.2と2.2で私の書いたオセロのプログラムを使ってスピードの比較でも暇な時にやってみたいと思います。

参考文献

Open Source Swift Under the Hood