Swift3新特性匯總


之前 Apple 在 WWDC 上已將 Swift 3 整合進了 Xcode 8 beta 中,而本月蘋果發布了 Swift 3 的正式版。這也是自 2015 年底Apple開源Swift之后,首個發布的主要版本(Swift 3.0),該版本實現了 Swift 演變過程中所討論並通過的90多個提議。這里我對 Swift 3 的新特性、新變化進行一個總結。


一、徹底移除在 Swift 2.2 就已經棄用的特性

這些特性在我們使用 Xcode 7.3 的時候就已經有告警提示,在 Swift 3 中已將其徹底移出。

1、棄用 ++ 與 -- 操作符

過去我們可以使用 ++ 與 -- 操作符來實現自增自減,現已廢棄。

var i = 0
i++
++i
i--
--i

可以使用復合加法運算(+=)與減法運算(-=),或者使用普通的加法運算(+)與減法運算(-)實現同樣的功能。

2、廢除C語言風格的for循環

我們過去可能習慣下面風格的 for 循環,現在也已廢棄。

現在可以使用 for-in 循環,或者使用 for-each 加閉包的寫法實現同樣的功能。

//for-in循環
for i in 1...10 {
    print(i)
} //for-each循環 (1...10).forEach {
    print($0)
}

3、移除函數參數的 var 標記

在 Swift 函數中,參數默認是常量。過去可以在參數前加關鍵字 var 將其定義為變量,這樣函數內部就可以對該參數進行修改(外部的參數任然不會被修改)。


var age = 22
add(age)
func add(var age:Int) {
    age += 1
}

現在這種做法已經被廢棄,Swift 3 不再允許開發者這樣來將參數標記為變量了。

4、所有函數參數都必須帶上標簽

過去如果一個函數有多個參數,調用的時候第一個參數無需帶標簽,而從第二個參數開始,必須要帶標簽。


let number = additive(8, b: 12)
func additive(a:Int, b:Int) -> Int{
    return a + b
}

現在為了確保函數參數標簽的一致性,所有參數都必須帶上標簽。


let number = additive(a: 8, b: 12)
func additive(a:Int, b:Int) -> Int{
    return a + b
}

這個變化可能會造成我們的項目代碼要進行較大的改動,畢竟涉及的地方很多。所以蘋果又給出了一種不用給第一個參數帶標簽的解決方案。即在第一個參數前面加上一個下划線。
(不過這個只是方便我們代碼從 Swift2 遷移到 Swift3 的一個折中方案,可以的話還是建議將所有的參數都帶上標簽。)

let number = additive(8, b: 12)
func additive(_ a:Int, b:Int) -> Int{
    return a + b
}

5、函數聲明和函數調用都需要括號來包括參數

我們可以使用函數類型作為參數 ,對於一個參數是函數、返回值也是函數的函數。原來我們可能會這么寫:

func g(a: Int -> Int) -> Int->Int { ... }

當這樣非常難以閱讀,很難看出參數在哪里結束,返回值又從哪里開始。在 Swift 3 中變成這么定義這個函數:

func g(a:(Int) -> Int) -> (Int) -> Int { ... }

6、Selector 不再允許使用 String

假設我們給按鈕添加一個點擊事件響應,點擊后執行 tapped 函數。以前可以這么寫:

button.addTarget(responder, action: "tapped", forControlEvents: .TouchUpInside)

但由於按鈕的 selector 寫的是字符串。如果字符串拼寫錯了,那程序會在運行時因找不到相關方法而崩潰。所以 Swift 3 將這種寫法廢除,改成 #selecor()。這樣就將允許編譯器提前檢查方法名的拼寫問題,而不用再等到運行時才發現問題。

button.addTarget(self, action:#selector(tapped), for:.touchUpInside)

二、Swift 3 的新特性

1、內聯序列函數sequence

Swift 3 新增了兩個全局函數:sequence(first: next:) 和 sequence(state: next:)。使用它們可以返回一個無限序列。下面是一個簡單的使用樣例,更詳細的介紹可以我的另一篇文章:Swift - 內聯序列函數sequence介紹(附樣例)

// 從某一個樹節點一直向上遍歷到根節點
for node in sequence(first: leaf, next: { $0.parent }) {
    // node is leaf, then leaf.parent, then leaf.parent.parent, etc.
}

// 遍歷出所有的2的n次方數(不考慮溢出)
for value in sequence(first: 1, next: { $0 * 2 }) {
    // value is 1, then 2, then 4, then 8, etc.
}

2、 key-path不再只能使用String

這個是用在鍵值編碼(KVC)與鍵值觀察(KVO)上的,具體 KVC、KVO 相關內容可以參考我原來寫的這篇文章:Swift - 反射(Reflection)的介紹與使用樣例(附KVC介紹)
我們還是可以繼續使用 String 類型的 key-Path:

//用戶類
class User: NSObject{
    var name:String = ""  //姓名
    var age:Int = 0  //年齡
}
//創建一個User實例對象
let user1 = User()
user1.name = "hangge"
user1.age = 100
//使用KVC取值
let name = user1.value(forKey: "name")
print(name)
//使用KVC賦值
user1.setValue("hangge.com", forKey: "name")

但建議使用新增的 #keyPath() 寫法,這樣可以避免我們因為拼寫錯誤而引發問題。

//使用KVC取值
let name = user1.value(forKeyPath: #keyPath(User.name))
print(name) //使用KVC賦值 user1.setValue("hangge.com", forKeyPath: #keyPath(User.name))

3、Foundation 去掉 NS 前綴

比如過去我們使用 Foundation 相關類來對文件中的 JSON 數據進行解析,這么寫:

let file = NSBundle.mainBundle().pathForResource("tutorials", ofType: "json")
let url = NSURL(fileURLWithPath: file!)
let data = NSData(contentsOfURL: url)
let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: []) print(json)

在 Swift 3 中,將移除 NS 前綴,就變成了:

let file = Bundle.main.path(forResource: "tutorials", ofType: "json")
let url = URL(fileURLWithPath: file!)
let data = try! Data(contentsOf: url)
let json = try! JSONSerialization.jsonObject(with: data) print(json)

4、除了M_PI 還有 .pi

在過去,我們使用 M_PI 常量來表示 π。所以根據半徑求周長代碼如下:

let r = 3.0
let circumference = 2 * M_PI * r

在 Swift 3 中,π 提供了 Float,Double 與 CGFloat 三種形式(Float.pi、Double.pi、CGFloat.pi),所以求周長還可以這么寫:

let r =  3.0
let circumference = 2 * Double.pi * r //我們還可以將前綴省略,讓其通過類型自動推斷 let r = 3.0
let circumference = 2 * .pi * r

5、簡化GCD的寫法

關於 GCD,我原來寫過一篇相關文章:Swift - 多線程實現方式(3) - Grand Central Dispatch(GCD)
過去寫法采用 C 語言的風格,初學者可能會不大適應。比如創建一個簡單的異步線程:

let queue = dispatch_queue_create("Swift 2.2", nil)
dispatch_async(queue) {
    print("Swift 2.2 queue")
}

Swift 3 取消了這種冗余的寫法,而采用了更為面向對象的方式:

let queue = DispatchQueue(label: "Swift 3")
queue.async {
    print("Swift 3 queue")
}

6、Core Graphics的寫法也更加面向對象化

Core Graphics 是一個相當強大的繪圖框架,但是和 GCD 一樣,它原來的 API 也是 C 語言風格的。
比如我們要創建一個 view,其內部背景使用 Core Graphics 進行繪制(紅色邊框,藍色背景)。過去我們這么寫:
class View: UIView {
    override func drawRect(rect: CGRect) {
        let context = UIGraphicsGetCurrentContext()
        let blue = UIColor.blueColor().CGColor
        CGContextSetFillColorWithColor(context, blue)
        let red = UIColor.redColor().CGColor
        CGContextSetStrokeColorWithColor(context, red)
        CGContextSetLineWidth(context, 10)
        CGContextAddRect(context, frame)
        CGContextDrawPath(context, .FillStroke)
    }
}

let frame = CGRect(x: 0, y: 0, width: 100, height: 50)
let aView = View(frame: frame)

在 Swift 3 中改進了寫法,只要對當前畫布上下文解包,之后的所有繪制操作就都基於解包對象。

class View: UIView {
    override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else {
            return
        }
        let blue = UIColor.blue.cgColor
        context.setFillColor(blue)
        let red = UIColor.red.cgColor
        context.setStrokeColor(red)
        context.setLineWidth(10)
        context.addRect(frame)
        context.drawPath(using: .fillStroke)
    }
}

let frame = CGRect(x: 0, y: 0, width: 100, height: 50)
let aView = View(frame: frame)

7、新增的訪問控制關鍵字:fileprivate、open

在 Swift 3 中在原有的 3 個訪問控制關鍵字 private、public、internal 外。又添加了2個新關鍵字 fileprivate、open。它們可以看成是對原來 private 和 public 的進一步細分。具體使用方法和介紹可以看我寫的另一篇文章:Swift - Swift3新增的兩個訪問控制關鍵字介紹(fileprivate、open)

三、一些語法的修改

1、數組排序:sort()與sorted()

過去數組排序的兩個方法:sortInPlace() 和 sort(),現在分別改名成 sort() 和 sorted()
sort() 是直接對目標數組進行排序。sorted() 是返回一個排序后的數組,原數組不變。
var array1 = [1, 5, 3, 2, 4]
array1.sort()
print(array1)  //[1, 2, 3, 4, 5] var array2 = [1, 5, 3, 2, 4]
let sortedArray = array2.sorted()
print(array2)  //[1, 5, 3, 2, 4] print(sortedArray)  //[1, 2, 3, 4, 5]

2、reversed()與enumerated()

過去 reverse() 方法實現數組反轉,enumerate() 方法實現遍歷。現這兩個方法都加上 ed 后綴(reversed、enumerated)

for i in (1...10).reversed() {
    print(i)
}
let array = [1, 5, 3, 2, 4]
for (index, value) in array.enumerated() {
    print("\(index + 1) \(value)")
}

3、CGRect、CGPoint、CGSize

過去的 CGRectMake、CGPointMake、CGSizeMake 已廢棄。現改用 CGRect、CGPoint、CGSize 代替。

//Swift 2
let frame = CGRectMake(0, 0, 20, 20)
let point = CGPointMake(0, 0)
let size = CGSizeMake(20, 20) //Swift 3 let frame = CGRect(x: 0, y: 0, width: 20, height: 20)
let point = CGPoint(x: 0, y: 0)
let size = CGSize(width: 20, height: 20)

4、移除了API中多余的單詞

  • XCPlaygroundPage.currentPage 改為 PlaygroundPage.current
  • button.setTitle(forState) 改為 button.setTitle(for)
  • button.addTarget(action, forControlEvents) 改為 button.addTarget(action, for)
  • arr.minElement() 改為 arr.min()
  • arr.maxElement() 改為 arr.max()
  • attributedString.appendAttributedString(anotherString) 改為 attributedString.append(anotherString)
  • names.insert("Jane", atIndex: 0) 改為 names.insert("Jane", at: 0)
  • NSBundle.mainBundle() 改為 Bundle.main
  • UIDevice.currentDevice() 改為 UIDevice.current
  • NSData(contentsOfURL) 改為 Data(contentsOf)
  • NSJSONSerialization.JSONObjectWithData() 改為 JSONSerialization.jsonObject(with)
  • UIColor.blueColor() 改為 UIColor.blue


5、枚舉成員變成小寫字母開頭

Swift 3 將枚舉成員當做屬性來看,所以現在使用小寫字母開頭而不是以前的大寫字母。
.system //過去是:.System
.touchUpInside //過去是:.TouchUpInside
.fillStroke //過去是:.FillStroke
.cgColor //過去是:.CGColor

6、@discardableResult

在 Swift 3 中,如果一個方法有返回值。而調用的時候沒有接收該方法的返回值,Xcode 會報出警告,告訴你這可能會存在潛在問題。

2016092716530979317[2]

除了可以通過接收返回值消除警告。還可以通過給方法聲明 @discardableResult 來達到消除目的。

.system //過去是:.System
.touchUpInside //過去是:.TouchUpInside
.fillStroke //過去是:.FillStroke
.cgColor //過去是:.CGColor

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        printMessage(message: "Hello Swift 3!")
    }
    @discardableResult
    func printMessage(message: String) -> String {
        let outputMessage = "Output : \(message)"
        return outputMessage
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

原文出自:航歌網


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM