七、函數與閉包
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 {
//多參被包裝為數組
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) {
func1(3, param2: { (count) in
print(count)
}, param3: { (count) in
})
還有一種更加簡單的閉包書寫方法,如果閉包類型是确定的,全完可以省略小括号中的參數名稱與閉包格式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}
八、類與屬性
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方法原理上将屬性的存取與其他邏輯操作進行了分離,抽象出了一種計算屬性,示例如下:
var count:Int
//實際上并不存在privateCount屬性 通過pricatecount來操作count的值
var privateCount:Int{
get{
return count;
set {
count=newValue+100
init(){
count=200