バージョンとか
Xcode 8.3.1
Swift 3.1
作業日数 2日
※Swiftのバージョンは下記のコマンドで調べられるよ!
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -version
前提的な
実際に自分のプロジェクトででたエラーのまとめになるので、プロジェクトごとに別のエラーが出たり出なかったりすると思います。
- コンパイルエラーのかんたんな修正方法
該当のエラーを選択しながら、Xcode の Editor メニューに Fix All in Scope という項目があってこれを選択するとファイルの赤丸を一気に全部なおしてくれます。(Command + Option + Control + F)
※ただし、結構 な頻度で動かなかったりするのでなんかエラー数が減らないなぁと思ったら1つずつ自動修正するといいです。あと、連打するとなおったりとかもします。
- Swift3の命名規則とかに関しては下記がすごくよくまとまってます。
【Swift 3 を書くときに知っておきたい API デザインガイドライン】
https://www.slideshare.net/tomohirokumagai54/swift-3-api-loveswift-akibaswift
本題
Xcodeのバグ?編
一部privateがfileprivateに書き換えられない箇所があった
private let test = "test"
private let test = "test"
fileprivate let test = "test"
なんか知らないが一部fileprivateになっていない変数や関数がありました。
そんな変数このクラスにないよ的なエラーメッセージがでたらこちらを疑うといいです。
unrecognized selector sent to instance
@IBOutlet, @IBAction の記述が消える
@IBOutlet private weak var moreButton: UIButton!
@IBAction private func moreButtonTapped(sender: UIButton) {
}
fileprivate weak var moreButton: UIButton!
fileprivate func moreButtonTapped(_ sender: UIButton) {
}
@IBOutlet fileprivate weak var moreButton: UIButton!
@IBAction fileprivate func moreButtonTapped(_ sender: UIButton) {
}
private
をfileprivate
に修正する際に、@IBOutletの記述が削除されてしまい、アプリは起動するが起動直後に落ちます。
再度@IBOutlet、@IBActionの記述をすればIBとの接続はやり直さなくても動きます。
※原因は不明ですが、再度つなぎ直さないといけない場合もありました。
IBAction の第1引数が省略されない
@IBAction func moreButtonTapped(sender: UIButton) {
}
@IBAction func moreButtonTapped(sender: UIButton) {
}
@IBAction func moreButtonTapped(_ sender: UIButton) {
}
Swift3では第1引数を省略する場合は明示的に_
を記述するようになったのですが、一部IBActionで_
の記述がないために、アプリが落ちてしまいました。こちらも_
を記述すれば自動的に接続されて動くようになります。
※こちらも原因は不明ですが、再度つなぎ直さないといけない場合もありました。
tableViewのdelegateメソッドやdataSouceメソッドの第一引数が省略されない&メソッド名が変わったけど 置換されない
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
}
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
}
func numberOfSections(in tableView: UITableView) -> Int {
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
}
optionalなメソッドだったりすると実装していなくてもエラーなどがでないので気づきにくかったです。
なぜか知らないがtableViewのデータが片っ端から表示されなくて、API周りから確認していったらまさかのdelegateメソッドが実装されていない(メソッド名が変わったので呼ばれない)だったとは....
breakpointをしかけても無反応だったのでめっちゃ焦りました。
Enum で一部 LowerCamelCase になおらないものがありました
enum Test: Int {
case Apple = 0
case Banana
}
switch test {
case Test.Apple
break
case Test.Banana
break
}
enum Test: Int {
case apple = 0
case Banana
}
switch test {
case Test.Apple
break
case Test.banana
break
}
enum Test: Int {
case apple = 0
case banana
}
switch test {
case Test.apple
break
case Test.Banana
break
}
なぜかはよくわかりませんが、UpperCamalCaseのままの部分があったり、LowerCamelCaseに変換されている部分があったりしてエラーが大量に出ました。case
とかでプロジェクト全体を検索して1つ1つ修正していきました...
Swift3の仕様編
dispatch_async を使わなくなりました
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
// your function here
})
// to run something in 0.1 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// your code here
}
AnyObjectで返ってきていた部分がAnyになりました
※もしかしたらアプデしたライブラリの仕様変更が原因かも
let anyObject = any as AnyObject
let test = anyObject["test"]
as
で簡単にキャストできるので一旦は問題ないかと思います。
型名取得にdynamicTypeを使わなくなりました
let text = "Hello!"
String(text.dynamicType)
let text = "Bonjour!"
String(describing: type(of: text))
OR
String(describing: String.self)
こちらXcodeが自動で修正してくれますが、今回のプロジェクトではことごとく変換時に修正されてしまいました...
これに関しては手動で直したほうがいいです。
http://dev.classmethod.jp/smartphone/iphone/swift-3-type-of/
NS prefix がなくなった(ほとんど)ことで名前が衝突しました
※これは普通は起こらないと思いますが...
let URL = NSURL(string: "https://sample.com")
let URL = Foundation.URL(string: "https://sample.com")
変数名がURL
だったために、URLクラスと名前が衝突してしまいました。Foundationをつければ動きますが、こういったことが起きないように命名規則はAppleに従っておきましょう...
NotificationのNameの指定がStringからNSNotification.Name 型に変わりました
NSNotificationCenter.defaultCenter().
addObserver(self,
selector: #selector(CaptureInfoFirstViewController.willEnterForeground),
name: UIApplicationWillEnterForegroundNotification,
object: nil)
NotificationCenter.default.
addObserver(self,
selector: #selector(CaptureInfoFirstViewController.willEnterForeground),
name: NSNotification.Name.UIApplicationWillEnterForeground,
object: nil)
nameの部分が変わっています。一旦の場合は上記で良いですが、ちゃんと書き直す場合は下記のリンクを参考に修正したほうがいいです。
NSDateがDateに変わったことでNSDate-Escort
が使えなくなった
NSDate型をライブラリで拡張していたのですが、Date型に変わってしまったため、拡張したメソッドやらプロパティやらが使えなくなってしまいました。なので、SwiftでDateの拡張として書き直しました。(下記のリンク参考)
よくよく考えたら作り直さなくてもライブラリの拡張しているクラス名をNSDateからDateに変えればよかったのかな?Objective-cからだとDateってつかえるのか?
MutableMutableCollectionのextensionでshuffleInPlaceとか実装しているとエラーになる
http://stackoverflow.com/questions/37843647/shuffle-array-swift-3
上記とかを参考にしてMutableMutableCollectionのextensionでshuffleInPlaceを実装しているとエラーが出ます。
extension MutableCollectionType where Index == Int {
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension MutableCollection where Index == Int {
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
let j = Int(arc4random_uniform(UInt32(endIndex - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
最後に
Swift3対応は大変だった気がしますがまとめて見るとそうでもなかったですね。
大体2日ぐらいあれば(プロジェクト規模によりますが)修正できました(一旦動かせるところまで)。
罠的なところが多いので他の移行記事などを読んでからとりかかると罠に引っかからずに、比較的はやく移行できるかもしれません。
参考
【Swift2.2 から Swift3 へ頑張って移行した話|Qiita】
http://qiita.com/takayama/items/096d7fa6780f232da142