Edited at

既存アプリの Xcode 7.3 + Swift 2.2 対応

More than 3 years have passed since last update.


概要

Xcode7.3にアップデートしたことで、Swiftのバージョンが2.2になりました。

これにより既存プロジェクトに大量にWarning, Errorが出たので対応したものをまとめました。

WarningのほとんどがSwift 3に向けてdeprecatedになったものの警告でした。

ここにある以外のWarningについても、GitHubのapple/swift-evolution をチェックすると原因がわかる思います。


Warning


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

swift-evolution: SE-0003


修正前

func sayHelloTo(var name: String) {

name = "Hello, \(name)."
print(name)
}


修正後

func sayHelloTo(name: String) {

var name = name
name = "Hello, \(name)."
print(name)
}


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

swift-evolution: SE-0007


修正前

var index: Int = 0

index++


修正後

var index: Int = 0

index += 1

--についても同様。


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

swift-evolution: SE-0007


修正前

// 昇順ループ

let array1: [Int] = [10, 20, 30, 40, 50]
for var i = 0; i < array1.count; i++ {
print("\(i): \(array1[i])")
}

// 降順ループ
var array2: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for var i = array2.count - 1; i >= 0; i -= 1 {
array2.removeAtIndex(i)
}
print(array2) // []


修正後

対応方法はたくさんあります。

// 昇順ループ

let array1: [Int] = [10, 20, 30, 40, 50]

// 0 ..< array1.count の Rangeに対して for-in
for index in 0 ..< array1.count {
print("\(index): \(element)")
}

// array1.enumerate()に対して for-in
for (index, element) in array1.enumerate() {
print("\(index): \(element)")
}

// array1.enumerate()に対して forEach
array1.enumerate().forEach { (index, element) in
print("\(index): \(element)")
}

// 降順ループ
var array2: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in (0 ..< array2.count).reverse() {
array2.removeAtIndex(i)
}
print(array2) // []

// 配列のインデックス配列を逆順にforEach
var array3: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
array3.indices.reverse().forEach {
array3.removeAtIndex($0)
}
print(array3) // []


Use '#selector' instead of explicitly constructing a 'Selector'


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

swift-evolution: SE-0022

NSNotificationCenter や UIControl などにメソッド名を渡す方法が変更になりました。


修正内容

文字列で指定されていたメソッド名を#selector(<Class>.<MethodName>)を使って指定します。

今までは文字列だけで参照されていたメソッドは、Xcode上でメソッドが呼び出されていることが捕捉できませんでしたが、#selector()に変わることで、メソッドが呼び出されていることがわかるようになります。


修正前

class SomeTableViewController: UITableViewController {

override func viewDidLoad() {
super.viewDidLoad()

refreshControl = UIRefreshControl()
refreshControl.addTarget(
self,
action: "refresh",
forControlEvents: .ValueChanged)
tableView.addSubview(refreshControl)
}

func refresh() {
}


修正後

class SomeTableViewController: UITableViewController {

override func viewDidLoad() {
super.viewDidLoad()

refreshControl = UIRefreshControl()
refreshControl.addTarget(
self,
action: #selector(SomeTableViewController.refresh),
forControlEvents: .ValueChanged)
tableView.addSubview(refreshControl)
}

func refresh() {
}


__FILE__ is deprecated and will be removed in Swift 3. please use #file


__LINE__ is deprecated and will be removed in Swift 3. please use #line


__FUNCTION__ is deprecated and will be removed in Swift 3. please use #function

swift-evolution: SE-0028

デバッグ用識別子の呼び出しが変わった。


This proposal renames the following identifiers:

__FILE__ -> #file

__LINE__ -> #line

__COLUMN__ -> #column

__FUNCTION__ -> #function (Added during review)

__DSO_HANDLE__ -> #dsohandle



修正前

print("\(__FILE__), \(__FUNCTION__), \(__LINE__)")


修正後

print("\(#file), \(#function), \(#line)")


Error


Use of unresolved identifier 'SomeEnumType'

Objective-Cの .h ファイルで定義している enum が Swiftファイルから参照できなくなりました。

@interfaceの内側で定義していたものを、外側に移動させるとエラーがなくなりました。


修正前

@interface Feedback : NSObject

typedef NS_ENUM(NSInteger, SomeEnumType) {
SomeEnumTypeNone = 0,
SomeEnumTypeA = 1,
SomeEnumTypeB = 2,
SomeEnumTypeC = 3,
}


修正後

typedef NS_ENUM(NSInteger, SomeEnumType) {

SomeEnumTypeNone = 0,
SomeEnumTypeA = 1,
SomeEnumTypeB = 2,
SomeEnumTypeC = 3,
}

@interface Feedback : NSObject


'(name: String, size: CGSize) -> UIFont' is not convertible to '(name: String, size: CGFloat) -> UIFont?'

UILabelfontプロパティにUIFontオブジェクトを代入しているところでエラーが発生しました。

原因は不明。


修正前

let label = UILabel()

if let font = UIFont(name: "AvenirNext-Medium", size: 12.0) { // UIFontのイニシャライザでエラー
label.font = font
}


修正後

let label = UILabel()

let descriptor = UIFontDescriptor(name: "AvenirNext-Medium", size: 12.0)
label.font = UIFont(descriptor: descriptor, size: 12.0)