Swift解讀專題一——Swift2.2語言預覽

專題一——Swift2.2語言預覽

1、引言

        本系列專題是我經過閱讀Swift2.2語言開發文檔,翻譯總結加上本身的理解整理而成。其中大部分結構和內容都來自開發文檔,有疏漏和錯誤之處,還望更多朋友指出,共同交流進步,個人QQ:316045346。編程

2、從HelloWorld開始

        在學習不少編程語言時,都是從HelloWorld入門,下面代碼就是一個完整的HelloWorld程序:數組

print("Hello, World!")

分析上面代碼,能夠發現Swift語言的3個十分明顯的特色:安全

1.開發者不須要引入輸入輸出相關的函數庫。閉包

2.在編寫代碼時,不須要在語句的結尾處添加分號。編程語言

3.全局的代碼就是程序的入口,不須要相似C系語言的main()方法來做爲程序入口。函數

3、常量與變量

        常量和變量是編程語言中最基礎的兩類數據類型,常量能夠理解爲爲某個值起一個特定的名字,常量一般提供給開發者用於某些只賦值一次但卻在程序中多處使用的量值。變量也能夠進行屢次修改。分別使用let和var建立常量和變量。例如:學習

let letValue = 4
var varValue = 8
varValue = 16

開發者在進行常量和變量的建立時,並不須要制定類型,編譯器與根據第一次賦值的類型來推斷出常量或者變量的類型,然而這並非說Swift語言不嚴格要求變量或常量的類型,一旦編譯器推斷了值的類型,以後開發者若要修改變量,則必須嚴格遵照既定的變量類型,不然編譯器會報錯。優化

        若是開發者第一次對變量或常量進行的賦值不可以使編譯器正確的推斷出常量或變量的類型,開發者也能夠經過冒號後跟類型的方式來強制定義變量或常量的類型,以下:spa

var varValue:Float = 8
varValue = 16.0

在Swift語言中,不存在隱式轉換的概念,這也是Swift語言更加安全的特性之一,這樣的設計能夠保證變量在任什麼時候候類型都被明確的指定。在進行類型轉換時,能夠經過類實例化的方式進行,示例以下:翻譯

//Float值轉成Int
letValue+Int(varValue)
//Int轉爲Float
Float(letValue)+varValue

對於在字符串中使用其餘類型的變量,Swift語言提供了一種更加便捷的寫法,使用\()的方式來轉換,小括號內爲變量的名稱,例如:

var strValue = "Hello"
//Hello16.0
strValue+"\(varValue)"

4、數組與字典

        數組與字典是最經常使用的兩種數據集合,在Swift語言中,使用[]來建立數組或字典,示例以下:

var array = [1,2,3]
var dic = [1:"one",2:"two",3:"three"]

同Int,Float類型的數據同樣,數組和字典在第一次賦值時,也會根據賦值的類型來推斷出變量類型,開發者一樣也能夠強制指定,以下:

var array:[Int] = [1,2,3]
var dic:[Int:String] = [1:"one",2:"two",3:"three"]

Swift容許建立或者從新賦值爲空的數據或者字典,可是這有一個前提條件,被賦值爲空的數據或字典必須是類型肯定的,示例以下:

//這樣寫會報錯
//var errorArray = []
//建立空的數據集合
//方式一
var array:[Int] = []
var dic:[Int:String] = [:]
//方式二
var array2 = [Int]()
var dic2 = [Int:String]()
//方式三
var array3 = [1]
var dic3 = [1:"1"]
array3 = []
dic3 = [:]

5、optional類型的值

        在理解optional類型的值以前,咱們能夠先來看一段C代碼:

int a=1;
if(a){
    
}else{
    
}

上面這段代碼對於C語言來講徹底沒有問題,當a爲非0值時,就表明條件爲真,在Swift語言中則不一樣,if選擇語句中的條件必須爲Bool類型的值,所以,對於某些能夠爲空的值,Swift中提供了optional類型,這種類型至關於對其餘實際類型進行了包裝,若是有值,則他拆包後爲相應類型的值,若是沒有值,則爲空值nil。示例以下:

var optionalString: String? = "Hello"
if optionalString == nil {
    
}

在Swift中,當if與let共同使用時,將會構成一種更加奇特的語法方式,這種方式對於處理optional類型的值十分方便,示例以下:

/*
 if let 後面賦值爲optional類型的值有這樣的效果
 若是optional的值不爲nil 則會走if條件爲真的語句塊而且將optional變量的值賦值給let常量 能夠在if爲真的語句塊中使用
 若是optional的值爲nil 則會走else語句塊 而且name常量被釋放 不能再else塊中使用
*/
if let name=optionalName {
    greeting = "Hello, \(name)"
}else{
    print(greeting)
}

除了if let語法外,還有一種方式能夠用來處理optional類型的值,示例以下:

var greeting = "Hello!"
greeting = "Hello" + (optionalString ?? "")

??運算符用來爲optional類型的值設置一個默認值,若是optional值爲nil,則會使用後面設置的默認值來代替。

        Swift語言的switch語句相比於C系的語言要強大的多,其不僅能夠用於判斷整型,其能夠處理任意類型的數據,一樣,它也不僅限於比較是否相等的運算,其能夠支持各類負責運算,示例以下:

let vegetable = "red pepper"
switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}

若是匹配上了一個case,程序會結束switch選擇,各個case之間是互斥的。

6、循環語句

        Swift2.2中,棄用了for i;param;param{}格式的循環語句,提供給開發者使用的循環語句主要有3種。

1.for in語句

for in語句多用於快速遍歷字典,示例以下:

let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
    //找出最大值
        if number > largest {
            largest = number
        }
    }
}
print(largest)

在for in循環中可使用一個索引來指定循環次數,經過這種方式能夠實現有序的遍歷操做,示例以下:

for i in 0..<10 {
    print(i)
}

2.while語句

while語句用於條件循環,直到再也不知足某個條件爲止,示例以下:

var n = 2
while n < 100 {
    n = n * 2
}
print(n)

3.repeat {}while語句

repeat{}while語句與C語言中的do{}while做用相同,保證至少循環一次。示例以下:

var m = 2
repeat {
    m = m * 2
} while m < 100
print(m)

7、函數與閉包

        Swift中的函數使用關鍵字func來標識,格式以下:

func name(param1,param2...)->returnValue{}

示例代碼以下:

func add(param1:Int,param2:Int) -> Int {
    return param1+param2
}
//下面表達式將返回8
add(5, param2: 3)

我比較了Swift語言與Objective-C、Java語言的函數特色:

        Objective-C實際上並無函數重載的概念,不一樣參數的函數實際上擁有不一樣的函數名,Objective-C的風格將參數名嵌套進函數名中,這樣有一個好處,開發者能夠經過函數名明確的知道此函數的用途以及每一個參數的意義,固然也有其侷限性,Objective-C的函數大多十分冗長,不夠簡潔。

        Java不一樣參的函數採用重載的方式,這樣的效果是,相同的函數名,參入不一樣的參數則會執行不一樣的操做,是不一樣的兩個方法,這樣的有點是使代碼十分簡潔,然而對開發者來講並不友好,開發者在開發時不能便捷的看出每一個參數的意義和用法。

        我的看法,Swift對函數的設計綜合了上面兩種語言的有事,參數列表與函數名分離,簡化了函數,同時,參數列表中保留了每一個參數的名稱,使開發者在調用函數時更加直觀。

        在Objective-C中,若是須要某個函數返回一組值,開發者一般會須要使用字典或者數組,這樣作有一個問題,在調用此函數時,返回值的意義十分模糊,開發者須要明確的知道其中數據的順序與意義。Swift中能夠採用返回元組的方式來處理一組返回值,示例以下:

//返回一組數據的函數
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    
    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }
    
    return (min, max, sum)
}
//元組數據
let statistics = calculateStatistics([5, 3, 100, 3, 9])
//經過名稱取元組中的最大值
print(statistics.max)
//經過角標取元組中的最小值
print(statistics.0)

        對於可變參數個數的函數,在Objective-C中,開發者大多會採用va_list指針的方式實現,示例以下:

-(void)myLog:(NSString *)str,...{//省略參數的寫法
    va_list list;//建立一個列表指針對象
    va_start(list, str);//進行列表的初始化,str爲省略前的第一個參數,及...以前的那個參數
    NSString * temStr = str;
    while (temStr!=nil) {//若是不是nil,則繼續取值
         NSLog(@"%@",temStr);
         temStr = va_arg(list, NSString*);//返回取到的值,而且讓指針指向下一個參數的地址
    }
    va_end(list);//關閉列表指針
}

在Swift語言中,實現這樣的函數要簡單的多,經過...來進行參數的省略,而且將這些省略的函數包裝爲數組傳入函數內部,示例以下:

func sumOf(numbers: Int...) -> Int {
    var sum = 0
    //多參被包裝爲數組
    for number in numbers {
        sum += number
    }
    return sum
}
sumOf()
sumOf(42, 597, 12)

與Java相似,Swift中的函數也支持嵌套操做,嵌套內部的函數可使用外部的變量,示例以下:

func returnFifteen() -> Int {
    var y = 10
    //嵌套函數
    func add() {
        y += 5
    }
    //調用
    add()
    return y
}
returnFifteen()

因爲函數也是一種特殊的數據類型,函數也能夠做爲返回值,示例以下:

func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment:((Int)->Int) = makeIncrementer()
increment(7)

一個函數也能夠做爲另外一個函數的參數來使用,示例以下:

//參數中有函數
func func1(param1:Int,param2:(count:Int)->Void) {
    param2(count: param1+1)
}
func tmpFunc(count:Int) -> Void {
    print(count)
}
//將函數做爲參數傳入
func1(3, param2: tmpFunc)

與Objective-C中的block對應,Swift中有閉包的概念來建立一個代碼塊,能夠理解爲閉包爲沒有名字的函數,使用{()in }格式來建立閉包,示例代碼以下:

var f:(count:Int)->Void = {(Count) in print(132) }
f(count:0)

經過這種寫法,開發者在將函數做爲參數傳遞時,無需再建立中間函數,示例以下:

//參數中有函數
func func1(param1:Int,param2:(count:Int)->Void,param3:(count:Int)->Void) {
    param2(count: param1+1)
}
func1(3, param2: { (count) in
        print(count)
    }, param3: { (count) in
        print(count)
})

還有一種更加簡單的閉包書寫方法,若是閉包類型是肯定的,全完能夠省略小括號中的參數名稱與閉包格式in,使用角標來獲取參數,示例以下:

//優化前
var f:(a:Int,b:Int)->Bool = {(a,b) in return a>b}
f(a: 3,b: 4)
//優化後
var f:(a:Int,b:Int)->Bool = {$0>$1}
f(a: 3,b: 4)

8、類與屬性

        Swift中使用class關鍵字來定義類,類內部能夠聲明與定義一些屬性與方法,類的實例對象能夠經過點語法來調用類的屬性和方法,示例以下:

class MyClass {
    var count = 100
    let name = "琿少"
    func run() {
        print("run 100 miter")
    }
}
var obj = MyClass()
let count = obj.count
let name = obj.name
obj.run()

類名加括號用於建立類的實例對象,能夠經過重寫init方法來重寫類的默認構造方法,若是這個類有繼承的父類,則須要遵照以下3條規則:

1.必須先將子類的屬性初始化完成。

2.調用父類的構造方法。

3.修改父類須要修改的屬性。

        在Swift中一樣也有set和get方法,只是這裏的set和get方法與Objective-C中的set和get方法有很大的不一樣,Objective-C中的get和set方法是截獲了屬性和存取過程,在其中加入額外的其餘操做,Swift中的set和get方法原理上將屬性的存取與其餘邏輯操做進行了分離,抽象出了一種計算屬性,示例以下:

class MyClass {
    var count:Int
    //實際上並不存在privateCount屬性 經過pricatecount來操做count的值
    var privateCount:Int{
        get{
            return count;
        }
        set {
           count=newValue+100
        }
    }
    let name = "琿少"
    func run() {
        print("run 100 miter")
    }
    init(){
        count=200
    }
}

Swift採用這樣的設計思路也有其必定的優化道理,我比較了一下,給你們舉一個最簡單的例子,在使用Objective-C進行iOS開發時,常常會遇到這樣的狀況,某個控件中有一個UILabel控件,開發者在不想將控件暴漏在.h文件中的狀況下常常會聲明一個NSString類型的變量,重寫此變量的set方法來完成對UILabel控件的賦值,仔細想來,實際上聲明的這個NSString變量徹底是多餘的,它只是爲了用來作中間值得傳遞,Swift的set和get方法就在這裏進行了優化。另外,在set方法中會自動生成一個命名爲newValue的變量做爲傳遞進來的值,開發者也能夠自定義這個變量的名稱,在set後加小括號便可,示例以下:

var privateCount:Int{
        get{
            return count;
        }
        set(myValue) {
           count=myValue+100
        }
    }

        Swift中也提供了監聽屬性賦值過程的方法,其使用的是willSet與didSet機制,示例以下:

class MyClass {
    var count:Int{
        //賦值前執行(除了第一次初始賦值) 將要賦值的值以newValue傳入
        willSet{
            print("will set \(newValue)")
        }
        //賦值後執行(除了第一次初始賦值) 原來的值以oldValue傳入
        didSet{
           print("did set \(oldValue)")
        }
    }
    let name = "琿少"
    func run() {
        print("run 100 miter")
    }
    init(){
        count=200
    }
}

9、枚舉和結構體

        Swift中的枚舉和C與Objective-C有很大的差異,在Swift中,枚舉也被做爲一種數據類型來處理,其中能夠添加函數方法。最基本的枚舉用法以下所示:

//枚舉能夠多個case並列 也能夠寫在一個case中以逗號分隔
enum MyEnum {
    case one
    case tew
    case three
    case Fir,Sec,Thr
}
var em = MyEnum.one

若是變量是類型肯定的枚舉,在賦值時能夠省略枚舉名,示例以下:

var em:MyEnum = .one

Swift中的枚舉還有一個原始值的概念,要使用原始值,必須在建立枚舉類型時設置原始值的類型,示例以下:

enum MyEnum:Int {
    case one=1
    case tew
    case three
    case Fir,Sec,Thr
}
var em = MyEnum.one.rawValue

若是原始值是Int類型,則默認從0開始依次遞增,開發者也能夠手動設置每一個枚舉值的原始值。一樣,也支持使用原始值來建立枚舉實例,以下:

var em = MyEnum(rawValue:1)

經過原始值實例的枚舉對象實際上回返回一個optional類型的值,若是傳入的原始值參數不能匹配到任何一個枚舉case,則可使用if let結構進行判斷處理。

        在枚舉中封裝方法示例以下:

enum MyEnum:Int {
    case one
    case tew
    case three
    case Fir,Sec,Thr
    func des() {
        switch self {
        case .one:
            print("one")
        default:
            print("else")
        }
    }
}
var em = MyEnum(rawValue:1)
em?.des()

        Swift中的枚舉也能夠添加附加值,在switch語句中取到對應的枚舉類型後,能夠獲取開發者設置的附加值進行邏輯處理,示例以下:

enum MyEnum {
//爲這個類型天啊及一組附加值
    case one(String,Int)
    case tew
    case three
    case Fir,Sec,Thr
    func des() {
        switch self {
        case .one:
            print("one")
        default:
            print("else")
        }
    }
}
var em = MyEnum.one("第一個元素", 1)
switch em {
//前面的let指定附加值爲常量 或者用var指定爲變量,括號內爲附加值參數名
case let .one(param1, param2):
    print("One param is  \(param1) and two param is  \(param2).")
default:
    print("else")
}

        Swift中使用struct關鍵字來進行結構體的建立,結構體的功能和類類似,支持屬性與方法,但不一樣的是,結構體在傳遞時會被賦值,類的實例則會以引用的方式傳遞。

專一技術,熱愛生活,交流技術,也作朋友。

——琿少 QQ羣:203317592

相關文章
相關標籤/搜索