12/08/2018, 13:21

Chỉnh sửa app để thích hợp với Xcode 7.3 và Swift 2.2 nào ^^

Như chúng ta đã biết, bản Xcode 7.3 vừa mới được update, và Swift đã được nâng lên version 2.2. Do đó khi Build lại các Project đã phát triển thì sẽ xuất hiện một số Error hay Warning trong Project. Bài viết này tác giả xin tổng hợp lại cách xử lý những vấn đề đó. Warning ở đây hầu hết là việc ...

Như chúng ta đã biết, bản Xcode 7.3 vừa mới được update, và Swift đã được nâng lên version 2.2. Do đó khi Build lại các Project đã phát triển thì sẽ xuất hiện một số Error hay Warning trong Project. Bài viết này tác giả xin tổng hợp lại cách xử lý những vấn đề đó.

Warning ở đây hầu hết là việc Apple hướng đến Swift 3 và không còn đồng ý với cú pháp đó nữa. Nếu các warning khác ở project của các bạn không xuất hiện trong bài viết này thì các bạn hãy check ở Github với địa chỉ apple/swift-evolution để tìm nguyên nhân nhé.

1.Warning

var param ở function đã bị warning và sẽ được remove trong Swift 3

swift-evolution: SE-003

Code khi chưa thay đổi :

func sayHelloTo(var name: String) {
    name = "Hello, (name)."
    print(name)
}

Code khi đã thay đổi :

func sayHelloTo(name: String) {
    var name = name
    name = "Hello, (name)."
    print(name)
}

++ cũng bị khuyến cáo và cũng sẽ bị remove trong Swift3

swift-evolution: SE-007

Code khi chưa thay đổi:

var index: Int = 0
index++

Khi đã thay đổi

var index: Int = 0
index += 1

-- cũng tương tự như vậy nhá =))

C-style cho các câu lệnh điều kiện cũng được khuyến cáo không sử dụng và sẽ bị loại bỏ sau này

swift-evolution: SE-0007

Code khi trước

// Loop tăng dần
let array1: [Int] = [10, 20, 30, 40, 50]
for var i = 0; i < array1.count; i++ {
    print("(i): (array1[i])")
}

// Loop giảm dần
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)   // []

Code thay đổi: (Có rất nhiều cách để thay đổi ^^ )

// Loop tăng
let array1: [Int] = [10, 20, 30, 40, 50]

// 0 ..< array1.count
for index in 0 ..< array1.count {
    print("(index): (element)")
}

// array1.enumerate()
for (index, element) in array1.enumerate() {
    print("(index): (element)")
}

// array1.enumerate() forEach
array1.enumerate().forEach { (index, element) in
    print("(index): (element)")
}

// Loop giảm
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

Việc gọi tên Method ở NSNotificationCenter và UIControl cũng đã thay đổi

Phần gọi tên hàm (action) hiện tại chúng ta chỉ cần ghi tên hàm để reference đến. Tuy nhiên ở phiên bản này việc chỉ định hảm cần theo cú pháp mới #selector(<Class>.<MethodName>).

Code trước:

class SomeTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

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

    func refresh() {
    }

Code sau khi sửa:

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 Tên định danh sử dụng trong debug được thay đổi cách gọi như sau:

__FILE__ -> #file
__LINE__ -> #line
__COLUMN__ -> #column
__FUNCTION__ -> #function (Added during review)
__DSO_HANDLE__ -> #dsohandle

Code trước:

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

Code sau khi sửa:

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

2.Error

Use of unresolved identifier 'SomeEnumType'

Swift file không reference được đến enum được định nghĩa ở file Objective-C .h những phần được định nghĩa ở bên trong @interface khi di chuyển ra bên ngoài sẽ bị lỗi

Code trước:

@interface Feedback : NSObject

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

Code sau khi sửa:

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?'

Property font của UILabel khi ta khai báo trực tiếp object UIFont vào sẽ bị lỗi. Nguyên nhân thì tác giả cũng chưa rõ lắm:

Code trước:

    let label = UILabel()
    if let font = UIFont(name: "AvenirNext-Medium", size: 12.0) {
        label.font = font
    }

Code sau khi sửa:

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