初見swift
- 打印‘hello world'
print("hello world");
教程
- 類型
- 基礎類型:
整型
Int
、浮點型Double
,Float
、布爾型Bool
、文本型String
。(還有Uint8,Int32等)
** 可以通過整型的min
和max
屬性來獲取對應類型的最小和最大值。**
- 集合類型:
Array
、Set
、Dictionary
。
- 特有類型:
元祖(Tuple)
可以允許創建或者傳遞一組數據,如可以作為函數返回值返回多個值
。
Optional 類型用于處理值缺失的情況
。
- 變量定義
- 如果代碼中有不需要改變的值,請使用
let
關鍵字將其聲明為常量
。只將需要改變的值聲明為var變量
。- 類型標注:可以在一行中定義多個同樣類型的變量,用
,
號分割,并在最后一個變量名后添加上類型標注
(var
+:
+空格
+類型
)即可。
var red,green,blue: Double;//示例- 命名:各種字符,包含 Unicode。常量和變量名不能包含
數學符號
、剪頭
、保留的 Unicode 碼位
、連線和制表符
。不能以數字
開頭。** 不能將命名好的常量和變量進行互換 **。
- 輸出
print(_:)
是一個用來輸出的全局函數,輸出的內容會在最后換行。print(_:appendNewline)
同1
,但唯一的區別是輸出內容最后不會換行。子串插值
將常量名或者變量名做占位加入至長子串重,swift 會做值替換。即\(var)
或者\(let)
形式插入子串中。
- 類型安全和類型推斷
- 類型安全
在編譯時進行類型檢查,將不匹配之類型標記為錯誤
。- 類型推斷
當沒有顯式制定類型時,swift會在編譯代碼時推斷選擇合適的類型,原理就是檢查你的賦值即可
。
- 數值型字面量
- 十進制:無前綴
- 二進制:前綴是
0b
- 八進制:前綴是
0o
- 十六進制:前綴
0x
- 數值類型轉換
整數轉換
用當前值來初始化一個期望的目標類型的新數字。
let two: Uint16 = 2_000;
let one: Uint8 = 1;
let and = two + Uint16(one);//目標常量即為Uint16類型
- ** 整數和浮點數轉換 **
整數和浮點數轉換必須顯式制定類型
let one = 3;
let two = 0.1415926;
let pi = Double(one) + two;let pi_int = Int(pi);//反向轉換
- 類型別名
類型別名
給現有類型定義另一個名字。使用typealias
關鍵字。
typealias scoreType = Uint16;//定義Uint16的別名
let oneScore: scoreType;//用別名定義常量
- 元組
元組
把多個值組合成一個復合值。內部的值可以是任意類型,可以有多種類型。
let http404Error = (404,"nor found");//定義一個類型為(Int,String)的元組
let (statuscode,_) = http404Error;//若只需要元組的部分值,可以用_
忽略不需要的元素。
let code = http404Error.0;//通過下標訪問元組的單個元素,下標從0開始。let http200Status = (code:200,des:"ok");//定義元組時給元素命名 print("status code is \(http200Status.code)");//通過命名的元素獲取值
元組在臨時組織值時很有用,但不適合創建復雜的數據結構。若數據結構不是臨時使用,請使用
類
或者結構體
。
- 可選類型
Optional來處理值缺省的情況:
有值=x
、無值=nil
。示例:String有一個
toInt
方法,但并不能保證所有String都能轉換成整型,故:
let string = "123";
let num: Int? = string.toInt();
上述成功返回Int
;但有可能失敗,故?
保證返回值只可能是Int
或什么也沒有
。let words: Int? = nil;
**
nil
不能用于非可選的常量和變量。若代碼中有常量
或變量
需處理值缺失
的情況,請將其聲明為可選類型
。
nil
在swift中不是空指針,而是一個確定的值
,用來表示值缺失
。
- if語句以及強制解析
可選值的_強制解析
當確定可選類型包含值時,可在可選值后面加一個!
來獲取值。即表示該可選值有值,可使用之
。若無可選值,則會運行時錯誤。
if let oneString: Int? = upString{
print("the string is (oneString!)");
}可選綁定
判斷可選類型是否包含值。若包含,則賦給一個臨時常量/變量;多用在if
和while
語句中來對可選類型的值進行判斷并賦值給一個常量/變量。示例代碼如上- 隱式解析可選類型:略。
- 錯誤處理
錯誤處理
應對程序執行中出錯的條件。拋出->捕捉->傳遞錯誤
//1. 一個函數可通過在聲明中添加throws
關鍵字來拋出錯誤消息,并且在其前置try
。
func canThrowAnError() throws{
//可能會拋出錯誤(當遇到錯誤條件,其能報錯;調用它的地方能拋出錯誤并合理處理)
}//2. `do`的聲明創建了一個新的包含作用域,使得錯誤能被傳播到一個或更多`catch`從句。 do{ try canThrowAnError()//3. ~ //沒有錯誤消息拋出 do some thing }catch Error.outofindex{//4. ~ //有一個具體錯誤消息拋出 } }catch{ //有一個錯誤消息拋出 }
- 斷言
斷言
若某個條件不滿足,代碼可能無法繼續執行,此時觸發一個斷言
來結束代碼運行并通過調試來找到問題所在。- 可以使用全局
assert
函數書寫一個斷言,當表達式=false是,觸發斷言。示例如下:
let age = -3;
assert(age>=0,"年齡不能小于零!");//因為age<0,故觸發斷言,終止運行代碼- 何時使用斷言:
- 下標索引太小或太大
- 函數傳值可能非法的驗證
- 可選值現在是nil,后面代碼中需要一個非nil值
- 斷言可導致應用終止運行,故盡量讓非法條件不出現;在app發布前斷言非法條件,有助于快速發現問題。
** --- **
基本運算符#
- 運算符:
+
、&&
、++i,i++
、a=b
、+-*/
、%
、a..<b
、a...b
、-a,!b
、a?b:c
、===
、!==
、a??b
。
a=b
賦值運算符不返回值。- 允許對浮點數進行取余運算
%
-9%4=-1;9%-4=1;9%4=1;
8%3.5=0.5;//浮點數取余,得 Doublea..<b
、a...b
區間取值:a<=i<b
、a<=i<=b
。+
可用于 String 拼接。如"hello,"+"world"
輸出hello,world
。===
、!==
恒等,判斷2個對象是否引用同一個實例。a ?? b
空合運算符,等價于(a != nil) ? a! : b
。
條件:a 必須是 Optional 類型;b 必須和 a 存儲值類型一致。
字符串和字符#
- 字符串
String
是字符Character
的有序集合。 -
字符串字面量
代碼中一段預定義
的字符串值。"**"用于為常量和變量提供初始值。 -
初始化空字符串
將空字符串字面量作為初始值,賦給變量,亦可初始化新的String
實例。
var emptyString = "";//空子串字面量 var emptyString2 = String();//初始化方法,空子串字面量
-
字符串可變性
即將特定字符串分配給一個var
并對其修改;或分配給一個let
并保證其不被修改。OC
中是通過NSString
和NSMutableString
來實現。 -
String
是值類型。let,var
賦值操作,或在func
傳遞時,進行值copy。即創建新副本傳遞。
但 swift 編譯器做了優化,除非必要,一般不會實際復制。 -
字符使用
通過for-in
循環遍歷String
中的Character
屬性,獲取每一個字符的值。
for character in "string"{
let oneCharacter: Character = character;//建立獨立的字符
} -
字符串和字符連接
可以通過+
、+=
、亦可通過append
將字符附加到一個String
的尾部。 -
字符串插值
類似于"hello,\(X)"
,其中X可以是var
、let
、字面量
、表達式
。 -
Unicode
swift中的字符串
和字符
是完全兼容Unicode
標準的。
Unicode
碼位范圍是U+0000
`U+D7FF`或者`U+E000`U+10FFFF
。不包括代理項碼位:U+D800
~U+DFFF
。 -
字符串字面量的特殊字符
包括\0
空字符、\\
反斜線、\t
水平制表符、\n
換行符、\r
回車符、\"
雙引號、\'
單引號。
Unicode標量:寫成\u{n}
,其中n
為任意1~8位十六進制的Unicode碼。
let one = ""yes"is yes";//"yes" is yes
let heart = "\u{2665}";//U+2665 可擴展的字形群集
每一個swift的
Character
類型代表一個可擴展字形群。
- 計算字符數量
調用
count(-:)
let string: String = "hello,world";
print(count:(count(string)));//
count(_:)
返回的字符數量并不總是和NSString的length相同
,原因便是前者計算可擴展字形群集。
- 訪問和修改字符串
通過String的
屬性
、方法
、下標
語法 訪問和讀取。
- 字符串索引:string.index<->對應著字符串中的每個字符的位置。不可用
Int
做索引
startIndex
、endIndex
分別對應字符串的第一個字符、最后位置。endIndex和子串長度相等,并非最后一個字符
* index的方法`predecessor()`、`successor()`分別得到當前索引的前一個、后一個索引。`advance(start:n:)`獲取特定索引。
* 全局函數`indices(string)`獲取一個涵蓋全部索引的范圍(Range),以在字符串中訪問分立的字符。
- 插入和刪除
insert()_:anIndex:
在字符串指定索引插入一個字符
。
var sayHello = "hello";
sayHello.insert(",",anIndex:sayHello.endIndex);//sayHello目前是"hello,"
splice(_:atIndex:)
在字符串的指定索引插入一個字符串
。
sayHello.insert("you!",anIndex:sayHello.endIndex);//sayHello目前是"hello,you!"
removeAtIndex(_:)
在字符串指定索引刪除一個字符
。
sayHello.removeAtIndex(sayHello.endIndex.predecessor());//sayhello目前是:"hello,you".(sayhello刪除前有一個換行符)
removeRange(_:)
在字符串指定索引刪除一個子字符串
。
let range = advance(sayHello.endIndex,-4)..<sayHello.endIndex;//a<=i<b
sayHello.removeRange(range);//sayhello目前是:"hello".
比較字符串
** Swift 提供了三種方式比較文本值:字符串字符相等
、前綴相等
、后綴相等
。**字符串/字符相等:使用
==
和!=
判斷是否相等前綴/后綴相等:使用字符串方法:
hasPrefix(_:)
、hasSuffix(_:)
來判斷字符串是否擁有特定的前綴/后綴。字符串的Unicode表示形式
** Swift提供的訪問字符串Unicode表示形式的方式:String.UTF8View
for codeUnit in myname.utf8 { print("\(codeUnit)"); }
集合類型
**Swift提供了Arrays
、Sets
、Dictionaries
三種基本的集合類型。
Array
是有序數據集。
Set
是無序無重復數據集。
Dictionary
是無序的key-value對
數據集。
Arrays
- 定義
Array<T>
:其中T
是數組中唯一允許存在的數據類型。亦可寫作[T]
簡單語法。
創建空數組
var cells = Int;//構造語法帶有默認值的數組
創建特定大小,并所有數據都被默認值的構造方法
var doubles = Double;//Doubel數組:[.0,.0,.0]通過2個數組相加創建新數組
同類型數組使用
+運算符
var otherDoubles = Double;
var newDoubles = doubles + otherDoubles;//新數組:[.0,.0,.0,1.0,1.0]用字面量構造數組
用一個或多個數值構造數組的方式
var names: [String] = ["zhou","wu","zheng","wang"];
- 訪問和修改數組
通過數組的方法
和屬性
、下標語法
進行訪問和修改數組操作。
cells.count
獲取數據數量
cells.isEmpty
檢測數組count是否為零
cells.apped(newCell)
在數組后面添加新的元素
cells +=[newCell1,newCell2]
在數組后面追加n個元素
cells[1]
= "newcell";//直接使用下標語法獲取和修改元素
cells.insert(newCell3,anIndex:0);
使用insert(_:anIndex:)
在某個索引值前
添加元素
cell = cells.removeAtIndex(0);
//使用removeAtIndex
移除特定索引值中
的元素,并返回該元素
- 遍歷Array
for cell in cells{};
//使用for-in
遍歷之
for(index,cell) in cells.enumerate(){};
//使用enumerate()
返回一個元組(索引值+元素)
** Set **
-
Set
用來存儲同類型的
、無序的
、單一的
元素集合。附加:可哈希的
-
Set<T>
,T
表示Set
允許存儲的類型。無等價的簡化形式。
- 創建和構造一個空Set:
var sexuals = Set<String>();//構造器創建特定類型空Set- 空數組字面量創建空Set
sexuals.insert("man");
sexuals = [];//依然是空的Set- 數組字面量創建Set.
并且可以使用簡化形式寫一個或者多個值作為Set元素
var sexuals: Set<String> = ["man","woman"];
- 訪問和修改Set
sexuals.count
獲取set的數量
sexual.isEmpty
檢查set是否為空set
sexuals.insert("unkown");
//insert(_:)
添加新元素
sexuals.remove("unkown");
//remove(_:)
刪除元素,并返回該元素;若無此值,返回nil。
sexuals.contains("man");
//contains(_:)
是否包含特定元素
- 遍歷set
for sexual in sexuals{}
//
for sexual in sexuals.sort(){}
//set.sort()
方法,返回一個排序的集合
- 完成set操作
圖示顯示了集合
a
和b
各種操作的結果
Set基本操作圖示1
- 使用
intersect(_:)
方法根據兩個集合中都包含的值創建的一個新的集合。- 使用
exclusiveOr(_:)
方法根據值在一個集合中但不在兩個集合中的值創建一個新的集合。- 使用
union(_:)
方法根據兩個集合的值創建一個新的集合。- 使用
subtract(_:)
方法根據不在該集合中的值創建一個新的集合。三個集合
a
b
和c
,以及通過懸浮區域表述集合間共享的元素
- 使用
是否等
運算符==
來判斷兩個集合是否包含全部相同的值。- 使用
isSubsetOf(_:)
方法來判斷一個集合中的值是否也被包含在另外一個集合中。- 使用
isSupersetOf(_:)
方法來判斷一個集合中包含的值是另一個集合中所有的值。- 使用
isStrictSubsetOf(_:)
或者isStrictSupersetOf(_:)
方法來判斷一個集合是否是另外一個集合的子集合或者父集合并且和特定集合不相等。- 使用
isDisjointWith(_:)
方法來判斷兩個結合是否不含有相同的值。
Dictionary
-
字典
是存儲多個同類型
、無序
的值的容器。每個值都關聯一個鍵,作為值的標識符。Key遵循哈希協議 -
Dictionary<Key,Value>
定義,亦可[Key:Value]
快捷定義。推薦后者
創建空字典
var nameDic = [Int: String()];//空的[Int: String]字典字典確定類型后,使用
[:]
創建空字典
var nameDic[1] = "chow";
nameDic = [:];
- 字典字面量
即是一種將寫1個或多個KV對作Dic集合的途徑
var nameDic:[Int: String] = [1:"chow",2,"pan"];
- 讀取和訪問字典
略 - 字典遍歷
略
控制流
- 循環:
for
、for-in
、 - 條件:
if
、switch
for循環
for-in
對一個集合里面每個元素執行一系列語句。區間
、數組元素
、字符串中字符
等。
for index in 1...5{};//index是每次循環遍歷開始時自動賦值的常量let
for _ in 1...5{};//若不需要每一項的值,用-替代之,來忽略對值的訪問
for
重復執行一系列語句直至達到某條件即可。一般通過計數器手動遞增
for var index=0;index<3;++index{}//不需括號while循環
while
、repeat=while
每次在循環開始時計算條件是否符合
whilecondition
{statements
}
repeat {statements
} whilecondition
;//類似于do-while
do-while
每次在循環結束時計算條件是否符合條件語句
if
條件較為簡單的情況下
ifstatements
{}else{}
switch
條件較復雜,較多時的情況下。會嘗試把某個值與若干模式進行匹配。
switch
必須是完備的。即每一個可能的值都必須至少有一個case
與之對應。默認分支
default
必須在最后。無需顯式展示
break
語句,即不是必須的。每個
case分支
后必須至少一條語句,但一個case
可包含多個模式:case v1,v2:
case分支
模式可以是一個值區間:case 1..25:
case分支
模式可以是一個元組:point坐標:case (_2...8,4):
或者case (_2,_):
_
匹配所有 值
值綁定:``case分支
模式允許將匹配的值綁定到一個臨時let
或var
上
where:``case分支
模式可以使用where
來判斷額外的條件let num = 10; switch num { case 1: respond; case 2,3: respond; case 4..<6: respond; case let seven where x == 7://where respond; case let other_num://等同于default了。 respond; case default: break; }
控制轉移語句
-
控制轉移語句
用于改變代碼的執行順序,實現代碼的跳轉:
continue
、break
、fallthrough
、return
、throw
。
continue
結束本次循環,開始循環體下一個循環break
結束整個循環體或switch的case代碼塊,跳轉至循環體外或switch外的第一行代碼。fallthrough
貫穿:一個case分支完成后,swift默認是不會自動落入下一個case分支中的,case末尾使用fallthrough
來使其能實現貫穿,即落入下一個case分支。fallthrough
不會檢查落入的case匹配條件
- 帶
tag
的語句
循環體
和switch代碼塊
均可以嵌套使用,以構造復雜的控制流。因此,顯式的指明break
和continue
影響的是哪一層循環體非常重要。
實現:可以用tag
來標記一個循環體
和switch代碼塊
,使用break
和continue
時,帶上該tag
即可控制其代表的循環體
和switch代碼塊
。
語法:tagName: while condition {statements}
- 提前退出
guard
和if
相似,區別在于guard
語句總是有個else
分句。?,不太清晰其機制,待查。
檢測API是否可用
Swift 有內置支持去檢查接口的可用性的,這可以確保我們不會不小心地使用對于當前部署目標不可用的API。
使用一個可用性條件在一個if
或guard
語句中去有條件的執行一段代碼,這取決于我們想要使用的API是否在運行時是可用的。if #available(iOS 9,OSX 10.10, *){ // 在 iOS 使用 iOS 9 APIs , 并且在 OS X 使用 OS X v10.10 APIs }else { // 回滾至早前 iOS and OS X 的API }
以上可用性條件指定在iOS, if 段的代碼僅僅在iOS9及更高可運行;在OS X,僅在OS X v10.10及更高可運行。最后一個參數, * ,是必須的并且指定在任何其他平臺上, if 段的代碼在最小可用部署目標指定項目中執行。
統一代碼:
if #available(`platform name` `version`, `...`, *) { `statements to execute if the APIs are available` } else { `fallback statements to execute if the APIs are unavailable` }
函數
- 定義和調用
定義
func sayHi(name: String)->String{
let greeting = "hi,(name)";
return greeting;
}調用
sayHi("pan");
- 函數參數和返回值
參數
和返回值
極為靈活,可以定義任何類型的函數。多重輸入參數,即多個參數
無參函數
多參量函數:
當調用超過一個參數的函數時,第一個參數后的參數根據其對應的參數名稱標記無返回值函數:無
->
和返回類型
func sayGoodbye(name: String){print("goodbye (name)");}
嚴格上來說,雖然沒有返回值被定義, sayGoodbye(_:) 函數依然返回了值。沒有定義返回類型的函數會返回特殊的值,叫 Void 。它其實是一個空的元組(tuple),沒有任何元素,可以寫成 () 。多重返回值函數
用元組
類型(亦可做可選
)讓多個值作為一個復合值從函數中返回。
func minMax(array:[Int])->(min: Int,max: Int)?{
if(array.isEmpty) return nil;
...
return (minNum,maxNum);
}函數參數名稱
函數參數均有一個外部參數名和一個本地參數名;
外參:標記傳遞給函數調用的參數
內參:實現函數時使用
func someFunction(firstParameterName: Int,secondParameterName: Int) {} someFunction(1,secondParameterName:2);//調用
一般情況下,第一個參數省略其外部參數名,第二個以后的參數使用其本地參數名作為自己的外部參數名.所有參數需要有不同的本地參數名,但可以共享相同的外部參數名.
- 指定外部參數名
在本地參數名前指定外部參數名,中間以空格隔開。若提供了外部參數名,在函數調用時,必須使用外參名。
func sayHello(to man: String,and otherMan:String){} sayHello(to:"pan",and:"you");//調用
- 忽略外部參數名
若不想為第二個以及以后的參數設置參數名,用_
代替參數名即可。
func sayHello(man: String,_ otherMan:String){} sayHello("pan","you");//調用.因第一個參數可忽略外參
- 默認參數值
可以為參數定義默認值,默認值被定義后,調用函數時可以忽略該參數。
func sayHello(man: String,_ otherMan:String = "you"){} sayHello("pan");//調用.第二個參數默認為"you"
將帶有默認值的參數放在函數參數列表的最后。這樣可以保證在函數調用時,非默認參數的順序是一致的,同時使得相同的函數在不同情況下調用時顯得更為清晰。
- 可變參數
可變參數:可以接受0個或多個值。在變量類型后面加(...)
來定義可變參數。
func sayHello(men: String...){ for man in men{} } sayHello("pan","you","she");//調用
傳入可變參數的值在函數體內當做這個類型的一個數組。
最多可以有一個可變參數,和它必須出現在參數列表中.
** 如果你的函數有一個或多個參數有默認值,還有一個可變的參數,將可變參寫在參數列表的最后。**
常量參數和變量參數
函數參數默認是常量
。此時在函數體中更改之,會導致編譯錯誤。
可以通過指定參數為變量參數,避免在函數中定義新的變量。
在參數名前加var
定義變量參數:
func sayHello(var man: String,_ otherMan:String = "you") {可以修改 man的值} let man_let = "pan"; sayHello(man_let);//調用.第二個參數默認為"you"
對變量參數所進行的修改在函數調用結束后便消失了,并且對于函數體外是不可見的。變量參數僅僅存在于函數調用的生命周期中。
- 輸入輸出參數
若想要一個函數可以修改參數的值,并且函數體運行結束后,修改仍然存在。將該參數定義為輸入輸出參數
即可。
參數定義:inout
加在參數定義前即可。該參數傳入函數,在函數體中修改,然后傳出函數,替換原來的值。
func swap(inout a: Int,inout b: Int){ let tempInt = a; a = b; b = tempInt; } var aInt = 3,bInt = 5; swap(&aInt,&bInt);//調用
- 只能將變量作為輸入輸出參數。你不能傳入常量或者字面量(literal value),因為這些量是不能被修改的。
- 當傳入的參數作為輸入輸出參數時,需要在參數前加 & 符,表示這個值可以被函數修改。
- 輸入輸出參數不能有默認值,而且可變參數不能用 inout 標記。如果你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
- 函數類型
函數類型 = 參數類型 + 返回值類型。如(Int,Int)->Int;()->Void
- 使用函數類型
函數類型同其它類型一樣使用。
var mathFunc = (Int,Int)->Int = addTwoInts;
matnFunc(2,4);//調用
注:相同匹配類型的不同函數亦可被賦值給同一個變量
- 函數類型作為參數類型
此時,可以將函數的部分實現交由函數的調用者。
func resultFunc(mathFunc: (Int,Int)->Int,_ a: Int,_ b: Int){
print("result:\(mathFunc(a,b)");
}
resultFunc(mathFunc,3,5);//調用
- 函數類型作為返回類型
即在函數返回->
之后寫一個完整的函數類型。
//func 1
func stepForward(input: Int)->Int{
return input + 1;
}
//func 2
func stepBackward(input: Int)->Int{
return input - 1;
}
//根據參數來返回上述函數的其中一個
func chooseStepFunc(isStepBack: Bool)->(Int)->Int{
return isStepBack? stepBackward:stepForward;
}
引用時,返回的函數的引用
保存在了var或let中。
- 嵌套函數
把函數定義在別的函數體中,即為嵌套函數。
func chooseStepFunc(isStepBack: Bool)->(Int)->Int{
func stepForward(input: Int)->Int{return input + 1;}
func stepBackward(input: Int)->Int{return input - 1;}
return isStepBack?stepBackward:stepForward;
}
閉包
閉包
是自包含的函數代碼塊,可以被傳遞和使用。與OC中的block
類似。
-
閉包
可以捕獲和存儲其所在上下文中任意let和var的引用。即閉合并包裹著這些let和var,故為閉包。
swift會為你管理在捕獲過程中涉及到的所有內存操作。 - 全局函數和嵌套函數實際上也是特殊的閉包。
- 閉包的三種形式:
- 全局函數:是一個
有名字
但不會捕獲任何值
的閉包。 - 嵌套函數:是一個
有名字
并可以捕獲其封閉函數域內值
的閉包。 - 閉包表達式:是一個利用輕量級語法所寫的
可以捕獲其上下文中let和var
的匿名閉包。
- 全局函數:是一個
- 閉包的優化:
- 利用上下文推斷
- 隱式返回單表達式閉包,即單表達式閉包可以省略return關鍵字
- 參數命縮寫
- 尾隨閉包語法
- 閉包表達式
嵌套函數
是一個在復雜函數中方便進行命名和定義自包含代碼模塊
的方式。
閉包表達式
利用簡潔語法構建內聯閉包的方式。
示例:Swift 標準庫提供了名為 sort 的函數,會根據您提供的用于排序的閉包函數將已知類型數組中的值進行排序。 一旦排序完成, sort(:) 方法會返回一個與原數組大小相同,包含同類型元素且元素已正確排序的新數組。原數組不會被 sort(:) 方法修改。
1. 參數是一個普通函數的方式 let names = ["chow","alex","barry","danel"];//逆序排序前的數組 func backwards(s1: String,s2: String)->Boll{ return s1>s2; } var reversed = names.sort(backwards);//調用閉包,輸出: ["danel","chow","barry","alex"] 2. 閉合表達式語法 { (parameters)->returnType in statements; }
let reversed = names.sort( { (s1: String,s2: String)-> Bool in
return s1>s2;
})
閉包的函數體部分由關鍵字 in 引入。 該關鍵字表示閉包的參數和返回值類型定義已經完成,閉包函數體即將開始。
- 根據上下文推斷類型:
reversed = names.sort({s1,s2 in return s1>s2})
- 單表達式閉包隱式返回
單行表達式閉包可以通過隱藏return
關鍵字來隱式返回單行表達式的結果。
reversed = names.sort({s1,s2 in s1>s2})
- 參數名稱縮寫
Swift 自動為內聯函數提供了參數名稱縮寫功能,您可以直接通過 $0 , $1 , $2 來順序調用閉包的參數。
in
關鍵字也同樣可以被省略,因為此時閉包表達式完全由閉包函數體構成。
reversed = names.sort({$0>$1})
尾隨閉包
將一個很長的閉包表達式作為函數最后一個參數,可以使用
尾隨閉包
來增強函數的可讀性-
尾隨包:是一個書寫在函數括號之后的
閉包表達式
,函數支持將其作為最后一個參數調用func funcTakeClosure(closure:()->Void){函數體} //不使用尾隨包的調用 funcTakeClosure( {閉包主體} ) //使用尾隨包 funcTakeClosure(){ 閉包主體 }
//示例
reversed = names.sort(){$0>$1} let digitNames = [ 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: > "Nine" ] let numbers = [16, 58, 510] let string = numbers.map() { (var number)->String in var output = ""; while number>0{ output = digitNames[number%10]! + output; number /= 10; } return output; } //輸出結果:["OneSix", "FiveEight", "FiveOneZero"]
- 捕獲值
- 閉包可以在其定義的上下文中捕獲常量或變量。 即使定義這些常量和變量的原域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。
- Swift最簡單的閉包形式是嵌套函數,也就是定義在其他函數的函數體內的函數。 嵌套函數可以捕獲其外部函數所有的參數以及定義的常量和變量。
示例:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
-
incrementer
函數并沒有任何參數,但是在函數體內訪問了runningTotal
、amount
。這是因為其通過捕獲在包含它的函數體內已經存在的runningTotal
、amount
的引用而實現。捕獲了變量引用,保證了runningTotal
、amount
變量在調用完makeIncrementor
函數后不會消失,并且保證了在下一次執行incrementor
函數時,runningTotal
可以繼續增加。 - 注意: 為了優化,Swift可能會捕捉和保存一份對值的拷貝,如果這個值是不可變或是在閉包外的。 Swift同樣負責被捕捉的所有變量的內存管理,包括釋放不被需要的變量。
let incrementByTen = makeIncrementor(forIncrement: 10)
incrementByTen()// 返回的值為10
incrementByTen()// 返回的值為20
incrementByTen()// 返回的值為30
閉包是引用類型
-
枚舉
枚舉
一個通用類型的一組相關值。
枚舉成員
對應一個原始值
,該值可以是:字符串
、字符
、整型
或者浮點數
。并且也可以不必為其提供原始值。- 枚舉語法
enum Sexual{ case man case woman,unkown } //引用:一旦確定是enum類型后,可以使用縮寫語法 var you = Sexual.man; //change you = .woman;
枚舉成員被創建時并不賦予一個默認的Int值。
- 匹配枚舉值和switch語句
Sexual you = .man;
switch you{
case .man:
//is a man
case .woman:
//is a woman
}
* `switch`在判斷枚舉值時,必須窮舉所有可能的值。
* 實在不需要部分值時,使用`default:`來涵蓋一部分。
- 相關值(略)
- 原始值
相關值的另一種選擇:枚舉成員可以被默認值(原始值
)賦值,其中原始值
具有相同的類型。
枚舉成員存儲ASCII碼示例
enum Sexual: Int{
case man = 1
case woman = 2
case unkown = 0
}
//此處原始值 類型為Int,且每個原始值在枚舉聲明中是唯一性的。
原始值的隱式賦值:其為Int或String類型時,不需要為每一個成員賦值,將會自動賦值的。
如:當使用整數作為原始值時,隱式賦值的值依次遞增1。如果第一個值沒有被賦初值,將會被自動置為0。
如:當使用字符串作為枚舉類型的初值時,每個枚舉成員的隱式初值則為該成員的名稱。
使用枚舉成員的rawValue
屬性訪問該枚舉成員的原始值。
- 使用原始值初始化
枚舉
、枚舉變量
如果在定義枚舉類型的時候使用了原始值,那么將會自動獲得一個初始化方法,這個方法將原始值類型作為參數,返回枚舉成員或者 。你可以使用這種初始化方法來創建一個新的枚舉變量。
let se = Sexual(rawValue: 2);//se為Sexual?,且se = .woman
并非所有可能的 值都可以找到一個匹配的行星。正因為如此,構造函數可以返回一個可選的枚舉成員。
- 遞歸枚舉
遞歸枚舉
是一種枚舉類型,在它的枚舉中,有一個或多個枚舉成員擁有該枚舉其它成員最為相關值的情況。
使用遞歸枚舉時,編譯器會插入一個中間層。你可以在枚舉成員前加上 indirect 來表示這成員可遞歸;也可以在枚舉類型開頭加上 indirect 關鍵字來表示它的所有成員都是可遞歸的
類和結構體
見swift筆記2