Swift 2.1-3.1版本演進匯總

有一段時間沒有寫 Swift 了, 前段時間打算在工程中使用 Swift, 結果發現各種東西都變了, 由于點比較分散, 而且官方文檔沒有給出具體例子, 只是羅列了修改點, 有些點還不太好理解, 所以自己整理了一下變化, 主要是2.1-3.1的修改, 后續的更新應該也會繼續往下面添加, 不過排版的形式還在考慮是最新的排最上面還是最下面...

有必要舉出例子的都會盡量舉出的例子, 其它的個人覺得沒什么特別的就會翻譯略過, 具體還是要參考官網的 Revision History. 如有疑問或者錯漏, 希望留言, 大家一起交流.

Swift 2.2更新

*增加了條件編譯塊的內容

相當于增加了 C 語言里面的條件編譯宏, 這部分內容在后續的版本中還有增強, #if, #elseif, #else, #endif都和之前沒有太大的變化, 主要還是條件有比較多的修改, 可以支持 os 類型和版本, arch, 后續還增加了 Swift 的版本.

*在指定成員描述(Explicit Member Expression)小節中, 增加了僅僅通過名字和參數來區分方法/構造器的內容

標題比較難理解, 其實就是在2.2中判定方法重名的機制變了, 直接看例子:

class SomeClass {
    func someMethod(x: Int, y: Int) {}
    func someMethod(x: Int, z: Int) {}
    func overloadedMethod(x: Int, y: Int) {}
    func overloadedMethod(x: Int, y: Bool) {}
}
let instance = SomeClass()
 
let a = instance.someMethod              // 無法確定
let b = instance.someMethod(x:y:)        // 可以確定
 
let d = instance.overloadedMethod        // 無法確定
let d = instance.overloadedMethod(x:y:)  // 依然無法確定
let d: (Int, Bool) -> Void  = instance.overloadedMethod(x:y:)  // 可以確定

可以看到, 參數名也需要一致了, 如果參數名一致, 但是類型不一致則需要顯式寫上方法的類型.

*增加了#selector的形式獲取 selector

之前的版本都是用字符串來尋找 selector, 沒有提示, 很容易出錯, 而且不報錯, 比較坑爹, 2.2增加了用#selector尋找 selector

*在關聯類型和協議關聯類型小節中更新了用 associatedtype 來關聯類型的內容
// 2.2 以前
protocol Container {
    typealias ItemType  // <-- 之前為 typealias
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

// 2.2
protocol Container {
    associatedtype Item // <-- 修改為 associatedtype
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}
*更新了構造失敗小節中構造器在實例完全構造好之前返回 nil 的內容

仔細看了一下文檔中給出的例子, 沒有發現明顯的區別, 所以具體也不知道更新了哪里...

*在比較操作符小節中增加了元組的對比

元組的對比需要兩邊里面的類型是一致, 否則會報錯. 直接看官方的例子吧

(1, "zebra") < (2, "apple")   // true, 因為1<2, 后續的就不會比了
(3, "apple") < (3, "bird")    // true, 因為3==3, apple<bird
(4, "dog") == (4, "dog")      // true

(1,2) < ("aa", "bb") // error

*在關鍵字和標點小節中,增加了使用關鍵字作為外部參數名的內容

也就是說現在關鍵字作為參數的標簽也是可以的了. 如:

func keywordFunc(func x: Int, while y: String){}
*在聲明屬性小節中更新了關于 @objc 屬性的內容, 現在枚舉和它的 case 都可以使用這個屬性了

這里增加了一大段描述, 大概就是現在可以給枚舉加 @objc 屬性了, 然后如果要在 Objc 代碼里面使用的話, 類型會自動拼接為 {TYPE}{CASE}, 如:

// xxx.swift
@objc public enum SomeType: Int {
    case Custom
    case System
    case TypeOne
    case None
}

// xxx.m
SomeType type = SomeTypeCustom;

對 case 使用 @objc 沒有做多余的闡述, 應該和 class 的屬性用是一致的效果.

*更新了操作符小節中, 關于自定義操作符中包含點的內容

現在可以定義一個以點(.)開頭的操作符, 例如: 可以定義.+.操作符, 它會被當做一個獨立的操作符. 如果一個自定義操作符不是以.開頭的, 那么它也不能在后續中包含., 例如+.+會被當做是+后面跟著一個.+操作符

PS: 個人不太建議定義這種奇奇怪怪的操作符, 如果不能一眼看出其作用或者符合一般的認知習慣, 就會變成定義了一個函數叫 a 一樣無法理解.

*還是在重新拋出函數和方法小節中, 增加了重新拋出函數不能直接拋出錯誤

也就是說標記為rethrows的函數不能直接 throw 一個錯誤, 必須要在 do-catch 中拋出, 如:

func someFunction(callback: () throws -> Void) rethrows {
    do {
    
    } catch {
        throw AnotherError.error
    }
}
*在屬性監聽小節中, 增加了傳入 in-out 參數的時候, 觸發屬性監聽的內容

我覺得這算是之前的一個小bug, 老版本在傳入屬性作為 in-out 參數的時候并不會調用 willSet 和 didSet, 3.0解決了這個問題:

class Test {
    var num = 1 {
        didSet{
            print("will set")
        }
        willSet{
            print("did set")
        }
    }
}

func testInout( param x : inout Int ){
    x = 2
}

var test = Test()
testInout(param: &test.num)

*在 A Swift Tour中增加了錯誤處理

在Swift 簡介中增加了錯誤處理的小節

*更新了弱引用的圖標, 使得析構過程更加清晰
*移除了 C 風格的 for 循環, 前++, 后++和前--, 后--都被移除了
*移除了可變函數參數和柯里化函數的特殊語法

Swift 3.0 變動

// 2017.1.7增加

* GCD 的修改

GCD 在 Swift 3中得到了徹底的修改, 新語法更適合 Swift 的寫法. 例如:

DispatchQueue.global().async {
    // do something in global queue
}
 
DispatchQueue.main.async {
    // do something in main queue   
}

具體 GCD 使用細節可以看看WWDC 視頻或者官方文檔

*更新了函數章節的內容, 函數聲明小節中所有的參數都會默認獲得一個參數標簽了.

以下列代碼為例:

// 函數聲明未變
func someFunction(firstParameterName: Int, secondParameterName: Int) {

}

// 3.0前版本調用
someFunction(1, secondParameterName: 2)

// 3.0版本調用
someFunction(firstParameterName: 1, secondParameterName: 2)
*更新了高級操作符章節內容, 現在可以把自定義的操作符作為類型方法來定義了, 而不是之前的全局函數.

高級操作符之前沒有在系列文章中體現, 所以暫時不好對比了, 如果可能的話我把以前的文檔找出來對比一下. 總之, 看起來現在友好很多, 以前看 swift 的源碼的時候會發現一大堆的操作符定義...

*在訪問控制章節中增加了對 open 和 fileprivate 的解釋.

也就是說訪問控制又增加了2個級別, 之前 private 對應了現在的 fileprivate, 列一個列表來說明變化吧:

修飾符 3.0以前版本 3.0版本
open 與 public 一樣, 可以被外部引用
public 跨模塊可見 跨模塊可見
internal 模塊內部的任何源文件可見 模塊內部的任何源文件可見
private 同一個源文件內可見 當前類型可見
fileprivate 同一個源文件內可見

在3.0中 open 相比較于 public 的區別如下:

 1. open 僅可用于類以及類的成員變量
 2. 用 public 或者更嚴格的訪問級別定義的類, 只能在當前模塊(定義該類的模塊)被繼承
 3. 用 public 或者更嚴格的訪問級別定義的類成員變量, 只能在當前模塊被重載
 4. 用 open 定義的類既可以在當前模塊繼承, 也可以在任意引入該模塊的地方繼承
 5. 用 open 定義的類成員變量既可以在當前模塊重載, 也可以在任意引入該模塊的地方重載

上述的幾點變化都設計到繼承, 重載, 所以 open 僅可用于類和類的成員變量.

*函數中 inout 修飾符的位置發生了變化
// 3.0前
func swapTwoInts(inout a: Int, inout _ b: Int) {
    let t = a
    a = b
    b = t
}
var a = 1, b = 2
swapTwoInts(&a, &b)  // &去掉會報錯

// 3.0
var x = 10
func f(a: inout Int, b: inout Int) {
    a += 1
    b += 10
}
f(a: &x, b: &x) // Invalid, in-out arguments alias each other
*更新了逃逸閉包和自動閉包章節的 @noescape@autoclosure 的信息, 目前它們是類型信息, 而不是聲明屬性了.

@noescape被去除, 增加了正向表意的 @escaping, 位置也有所變化.

// 3.0以前
var completionHandlers: [() -> Void] = [] // 存儲閉包用
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
 closure()
 completionHandlers.append(closure) // error
}
func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
 completionHandlers.append(completionHandler)
}

// 3.0
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

@autoclosure沒有更名, 只是和 @escaping 一樣變了位置

// 3.0以前
func serveCustomer(@autoclosure customerProvider: () -> String) {
 print("Now serving \(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))

// 3.0
func serve(customer customerProvider: @autoclosure () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
*高級操作符章節增加了自定義 infix 操作符優先級組的信息

直接看文檔吧, 目前不打算深入了解, 看文檔

*一系列更新, 包括用 macOS 取代 OS X, Error 替代 ErrorProtocol, 諸如ExpressibleByStringLiteral的協議改名為StringLiteralConvertible.
*更新了泛型章節的 where語句中的泛型小節, 現在 where 語句被寫在了聲明的最后邊

直接看代碼對比來看where語句的變化吧

// 3.0以前
func allItemsMatch<
    C1: Container, C2: Container  // <-- 類型約束, 必須實現Container
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> // <-- 協議內部關聯類型必須相等, 關聯類型必須實現Equatable協議
    (someContainer: C1, _ anotherContainer: C2) -> Bool {

    // do something
}

// 3.0
func allItemsMatch<
    C1: Container, C2: Container>
    (_ someContainer: C1, _ anotherContainer: C2) -> Bool
    // where 語句的位置發成了變化, 被放在了尖括號外部
    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
        
    // do something
}
*更新了逃逸閉包的內容, 現在它默認是非逃逸閉包了

參考上面的變化

*更新了基礎章節中的 optional 綁定以及語句章節中 while 語句的內容, 現在 if, while 和 guard 語句用一個逗號分割的列表來替代了 where 語句, 例如:
// 3.0以前
if let firstNumber = Int("4") {
    if let secondNumber = Int("42") {
        if firstNumber < secondNumber && secondNumber < 100 {
            print("\(firstNumber) < \(secondNumber) < 100")
        }
    }
}
// Prints "4 < 42 < 100"

// 3.0
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
    print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"

*在流程控制中的 switch 中的 case 中添加了多種模式匹配.

其實就是說一個case分支現在可以寫多個模式匹配了, 如果用原來的寫法的話, 就應該要用 fallthrough來寫2個 case.

switch control expression {
case pattern 1:
    statements
case pattern 2 where condition:
    statements
case pattern 3 where condition,   <-- 這里
     pattern 4 where condition:
    statements
default:
    statements
}
*更新了關于函數類型的內容, 現在函數參數標簽不再屬于函數類型的一部分了

直接看看官方的例子:

func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}
 
var f = someFunction // 現在 f 的類型是 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void 了.
f = anotherFunction              // OK
f = functionWithDifferentLabels  // OK
 
func functionWithDifferentArgumentTypes(left: Int, right: String) {}
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
 
f = functionWithDifferentArgumentTypes     // Error
f = functionWithDifferentNumberOfArguments // Error
*在協議章節更新了協議組合的內容, 以及類型章節中協議組合使用了 Protocol1 & Protocol2的新用法
// 3.0以前
protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named, Aged>) { // <-- 區別
    print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)

// 3.0

protocol Named {
    var name: String { get }
}
protocol Aged {
    var age: Int { get }
}
struct Person: Named, Aged {
    var name: String
    var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) { // <-- 區別
    print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
*在動態類型描述的內容, 現在使用新的 type(of:)語法來獲取動態類型描述

typeof 的用法官方給了例子, 其實也就是相當于給了個全局的函數, 返回一個 Class 對象.

class SomeBaseClass {
    class func printClassName() {
        print("SomeBaseClass")
    }
}
class SomeSubClass: SomeBaseClass {
    override class func printClassName() {
        print("SomeSubClass")
    }
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯期的時候有一個靜態的類型-- SomeBaseClass, 在 runtime 的時候有一個動態的類型--SomeSubClass
type(of: someInstance).printClassName()
// 打印出"SomeSubClass"
*更新了航控制語句小節中使用#sourceLocation(file:line:)語法的內容

根據描述應該是可以自己制定代碼的文件名和行數, 一般作為診斷和 debug 來使用.

*更新了函數永不返回中使用新的 Never 類型

swift 定義了一種 Never 的類型, 它指示了函數或者方法不會返回到調用方

*更新了 In-Out 參數小節中的內容--只有非逃逸閉包可以捕獲 in-out 參數
*更新了默認參數值小節中關于默認參數的內容, 現在他們不能在函數調用中重新訂閱了
*更新了屬性章節中屬性參數使用冒號

主要是配合 @available來使用, 如下面的例子, @available后面接 typealias(只作用一個, 有多個 typealias 只會作用于下面第一個) 導致 MyProtocol在后續發布后并不能真正地 alias 為MyRenamedProtocol, 只是為編譯器提供了提示的信息, 報錯會有 fix-it 出現.

// 第一次版本發布
protocol MyProtocol {
    // protocol definition
}
// 后續發布版本重新命名了MyProtocol
protocol MyRenamedProtocol {
    // protocol definition
}
 
@available(*, unavailable, renamed: "MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol

enum SomeEnum: MyProtocol {  // <-- 這里報錯, 并出現 fix-it, 要求變為MyRenamedProtocol, 
//如果MyRenamedProtocol拼寫錯誤如寫成MyRenamedProtocolTest, fix-it 的結果也會編程MyRenamedProtocolTest
    
}
*在重新拋出函數和方法小節中增加了關于在 rethrowing 函數的catch block內部錯誤的內容.

直白的說, 增加了在標注為 rethrows 的函數/方法中, 只有出現一個異常語句, 基本可以理解為只能出現一個 try.

enum SomeError:Error {
    case error
}

enum AnotherError:Error {
    case error
}


func alwaysThrows() throws {
    throw SomeError.error
}
func someFunction(callback: () throws -> Void) rethrows {
    do {
        try callback()
//        try alwaysThrows()  // 去掉注釋就報錯
    } catch SomeError.error{
        throw AnotherError.error
    }catch AnotherError.error{
        
    }
}
*增加了#selector 的objc屬性的 getter 和 setter 方法描述.

之前的版本都是用字符串來尋找 selector, 沒有提示, 很容易出錯, 而且不報錯, 比較坑爹, 3.0增加了類似原來@selector 的形式, 而且更加好用了.

class SomeClass: NSObject {
    let property: String
    @objc(doSomethingWithInt:)
    func doSomething(_ x: Int) {}
    
    init(property: String) {
        self.property = property
    }
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
*增加了類型別名聲明小節中, 關于泛型的別名和在協議中使用別名的內容

類型別名可以使用泛型參數來給定一個已有的泛型起名,例如:

typealias StringDictionary<Value> = Dictionary<String, Value>
 
// 下面兩個 dictionary 都是一樣的類型
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]

類型別名用泛型參數聲明了時候, 參數是可以加限制的, 例如:

typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>

在協議內部, 類型別名可以提供一個更加簡短和方便的名字, 例如:

protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    typealias Element = Iterator.Element
}
 
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
    // ...
}
*更新了函數類型小節的內容, 現在參數的圓括號是必須的了

主要是因為元組的原因, ((Int, Int)) -> Void(Int, Int) -> Void還是有很明顯的區別的.

*更新了屬性章節中, @IBAction, @IBOutlet 和 @NSManaged會附帶@objc的內容

也就是說只要加上了上面三種屬性的其中之一, 就會自動加上 @objc屬性.

*在屬性章節中, 增加了 @GKInspectable 的內容

文檔的描述如下:

Apply this attribute to expose a custom GameplayKit component property to the SpriteKit editor UI.
應用此屬性來暴露一個自定義的 GameplayKit 組件屬性到 SpriteKit 編輯器的 UI 上

說實話, 沒有玩過 GameplayKit, 只能硬翻了 :p, 字面上的意思也還好理解 GK=gamekit, inspectable, 可檢測到的

*更新了可選協議要求小節的內容, 使得這部分代碼只用于 objc 變得更加清晰了
// 3.0以前
@objc protocol CounterDataSource {
    optional func incrementForCount(count: Int) -> Int
    optional var fixedIncrement: Int { get }
}

// 3.0
@objc protocol CounterDataSource {
    @objc optional func increment(forCount count: Int) -> Int
    @objc optional var fixedIncrement: Int { get }
}
*移除了函數聲明小節中, 在函數參數中顯式使用 let 的內容

以前記得是如果整個函數沒有對參數進行修改, 就要在參數中加上 let 來修飾, 看起來這個設定被丟棄了.

*移除了語句章節中, Boolean 協議的內容, 現在這個協議已經從 Swift 標準庫中移除了
*糾正了聲明屬性小節中對 @NSApplicationMain的描述

Swift 3.0.1 變動

*更新了 ARC 章節中, weak 和 unowned 引用的內容

weak和 unowned 因為已經找不到2.2的描述, 看了最新的描述, 和之前的理解沒有明顯的差距, 貌似都是增加了一個 NOTE,
weak 的 NOTE 是:

Property observers aren’t called when ARC sets a weak reference to nil.

weak 屬性被自動設置為 nil 的時候不會觸發屬性觀察方法

之前自動設置為 nil 的時候是會觸發屬性監聽的, 新版本改為不觸發了.

小 Tip: 如果要驗證老的邏輯, 可以在Build Settings里面Use Legacy Swift Language Version 設置為 Yes

unowned 的 NOTE 是:

The examples above show how to use safe unowned references. Swift also provides unsafe unowned references for cases where you need to disable runtime safety checks—for example, for performance reasons. As with all unsafe operations, you take on the responsiblity for checking that code for safety.

You indicate an unsafe unowned reference by writing unowned(unsafe). If you try to access an unsafe unowned reference after the instance that it refers to is deallocated, your program will try to access the memory location where the instance used to be, which is an unsafe operation.

上面的例子展示了如何安全地使用 unowned 引用. Swift 還提供了非安全的 unowned 引用, 來應付不需要在 runtime 時期做安全性檢查的場景, 例如為了提高性能. 如其它的非安全操作, 你需要自己為代碼安全性負責.

用unowned(unsafe)來標記非安全的 unowned 引用. 如果你嘗試訪問一個非安全引用的實例, 而且它已經被析構了, 進程會訪問這個實例之前存在的內存空間, 這是個不安全的操作.

這個 NOTE 說明 Swift 提供了一種新的, 高性能的引用方式, 只是要付出安全性的代價.

*在聲明修飾符章節中增加了unowned, unowned(safe), 和 unowned(unsafe)的說明

上面已經有部分說明了
unowned(safe)unowned的顯式寫法, 也就是說, unowned 默認就是unowned(safe).
unowned(unsafe)unowned(safe)的區別主要是, unowned(safe)在訪問一個已經析構的對象, 會直接觸發 runtime error, 而unowned(unsafe) 則會去訪問這個實例曾經存在的地址, 其作用則是未知的.

*在Any 和 AnyObject 類型轉換小節中增加了關于當值是被期望是 Any 的時候使用 optional 的小記

The Any type represents values of any type, including optional types. Swift gives you a warning if you use an optional value where a value of type Any is expected. If you really do need to use an optional value as an Any value, you can use the as operator to explicitly cast the optional to Any, as shown below.

let optionalNumber: Int? = 3
things.append(optionalNumber)        // Warning
things.append(optionalNumber as Any) // No warning

Any 類型帶了了所有的類型, 包括 Optional 類型. 當你在需要 Any 類型的場合使用了 Optional 類型, 編譯器會給你一個警告. 如果你確實需要把 Optional 的值當做 Any 類型使用, 可以用as 操作符把它顯式轉化為Any, 如代碼所示.

*在 Expressions 章節中拆分了圓括號表述和元組表述

Swift 3.1 變動

*增加了包含 Where 從句泛型的拓展小節

現在拓展中的泛型也可以加 where 從句了, 來限定拓展的內容:

extension Stack where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let topItem = items.last else {
            return false
        }
        return topItem == item
    }
}

如果Stack 指定了沒有實現Equatable的類型, 在使用 isTop 的時候會報錯.

struct NotEquatable { }
var notEquatableStack = Stack<NotEquatable>()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
notEquatableStack.isTop(notEquatableValue)  // Error
*增加了聲明屬性小節中關于 Swift 版本的available屬性的內容

針對 Swift 版本也可以使用 @available 了, 之前都是平臺和系統版本之類的.
@available(swift version-number)

*更新了條件編譯塊小節中 Swift 版本數字的內容, 現在patch 版本號也允許使用了

可以理解為之前的條件編譯也加上了 Swift 版本的控制.

*更新了函數類型小節的內容. 現在 Swift 區分多參數函數和只有一個元組類型參數的函數了

直接上例子吧:

// 3.1以前:
func methodForTuple(t:(a: Int, b: Int, c: Int)){}    
func methodForMulti(a: Int, b : Int, c: Int){}

var tupleFunction = methodForTuple
tupleFunction = methodForMulti // 沒有報錯, 說明編譯器認為這兩個個函數是一個類型的

// 3.1之后就會報錯了, 因為暫時沒有更新 Xcode到最新版, 所以沒有驗證這一點

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代碼實現: 你不需要為了輸入輸出或者字符...
    restkuan閱讀 3,220評論 0 6
  • Swift 介紹 簡介 Swift 語言由蘋果公司在 2014 年推出,用來撰寫 OS X 和 iOS 應用程序 ...
    大L君閱讀 3,301評論 3 25
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,880評論 1 10
  • 當你難過了,你就跑吧。 當你失望了,你就跑吧。 當左邊的聲音罵你,你就往前跑吧。 當右邊的聲音拉你,你就往前跑吧。...
    米妮安M閱讀 154評論 0 0
  • Content-Type指示響應的內容,這里是text/html表示HTML網頁。請注意,瀏覽器就是依靠Conte...
    愛吃葡萄冰的鯨閱讀 307評論 0 0