七、函数与闭包
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)
八、类与属性
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
}
}