这个$i符号可以代替参数名字,代码进一步简化为:
letsortedAnimals=animals.sort{return$0<$1}
在一个独立的闭包内,return这个关键字是可以省略的。
最后声明的返回值就是闭包的返回值:
letsortedAnimals=animals.sort{$0<$1}
这简化很多了,但是我们不能止步于此!
对于字符串,有一个定义如下的比较函数:
funcBool
这个简单的小函数可以使你的代码简洁如下:
letsortedAnimals=animals.sort(<)
注意每一步的编译结果都相同,但是最后一步你的闭包里只有一个字符。
问题5–Swift1.0orlater
下面的代码创建了两个类Address和Person,并且创建了两个实例对象分别代表Ray和Brain.
classAddress{
varfullAddress:
String
varcity:
String
init(fullAddress:
String,city:
String){
self.fullAddress=fullAddress
self.city=city
}
}
classPerson{
varname:
String
varaddress:
Address
init(name:
String,address:
Address){
self.name=name
self.address=address
}
}
varheadquarters=Address(fullAddress:
"123TutorialStreet",city:
"Appletown")
varray=Person(name:
"Ray",address:
headquarters)
varbrian=Person(name:
"Brian",address:
headquarters)
假设Brain搬家到街对面的建筑物里,那么你会这样更新他的地址:
brian.address.fullAddress="148TutorialStreet"
这样做将会发生什么?
错误出在什么地方呢?
答案:
Ray同样会搬家到新的建筑物里面。
Address是一个引用类型类,所以无论你是通过ray或者brain访问headquarters,访问都是同一个实例化对象。
headquarters对象的变化也会引起ray和brain的变化。
你能想象如果Brain收到Ray的邮件或者相反Ray收到Brain的邮件,将会发生什么?
解决方案是创建一个新的Address对象赋值给Brain或者把Address声明成为结构体而不是一个类。
中级
问题1–Swift2.0orlater
思考下面的代码:
varoptional1:
String?
=nil
varoptional2:
String?
=.None
答案:
两者没有什么不同。
Optional.None(简称.None)是optional变量值初始化的标准方法,而nil只是.None语法的一种修饰。
事实上下面语句输出是正确的:
nil==.None//OnSwift1.xthisdoesn'tcompile.YouneedOptional
.None
记住枚举类型的Optional下的None:
enumOptional{
caseNone
caseSome(T)
}
问题2-Swift1.0orlater
下面是thermometer作为类和结构体的例子:
publicclassThermometerClass{
private(set)vartemperature:
Double=0.0
publicfuncregisterTemperature(temperature:
Double){
self.temperature=temperature
}
}
letthermometerClass=ThermometerClass()
thermometerClass.registerTemperature(56.0)
publicstructThermometerStruct{
private(set)vartemperature:
Double=0.0
publicmutatingfuncregisterTemperature(temperature:
Double){
self.temperature=temperature
}
}
letthermometerStruct=ThermometerStruct()
thermometerStruct.registerTemperature(56.0)
但是这段代码编译失败了,请问哪里报错,出错的原因是什么。
建议:
在使用Playground之前,认真阅读代码并思考。
答案:
代码的最后一行不会被编译通过。
ThermometerStruct结构体中正确的声明了一个mutating属性函数,它是用来改变结构体内部temperature属性的值的,但是编译器不通过的原因是,通过let创建的不可变的registerTemperature结构体调用了registerTemperature函数。
问题3–Swift1.0orlater
下面的代码输出是什么?
并说明理由。
varthing="cars"
letclosure={[thing]in
print("Ilove\(thing)")
}
thing="airplanes"
closure()
答案:
输出的是:
Ilovecars。
当闭包被声明的时候,抓捕列表就复制一份thing变量,所以被捕捉的值并没有改变,即使你给thing赋了一个新值。
如果你要忽视闭包中捕捉列表的值,那么编译器引用那个值而不是复制。
这种情况下,被引用变量的值的变化将会反映到闭包中,正如下面的代码所示:
varthing="cars"
letclosure={
print("Ilove\(thing)")
}
thing="airplanes"
closure()//Prints"Iloveairplanes"
问题4–Swift2.0orlater
下面是一个全局函数,这个函数的功能是计算数组中特殊值得个数。
(待校验)
funccountUniques(array:
Array)->Int{
letsorted=array.sort(<)
letinitial:
(T?
Int)=(.None,0)
letreduced=sorted.reduce(initial){($1,$0.0==$1?
$0.1:
$0.1+1)}
returnreduced.1
}
它使用了<和==运算符,他们限制着T(占位类型)的实际类型,也就是说T必须遵循Comparable协议。
你可以这样使用它:
countUniques([1,2,3,3])//resultis3
现在要求你重写上面的方法作为Array的扩展方法,然后你就可以这样写代码:
[1,2,3,3].countUniques()//shouldprint3
如何实现?
答案:
在Swift2.0中,泛类型可以使用类型约束条件被强制扩展。
但是假如这个泛类型不满足这个类型的约束条件,那么这个扩展方法既不可见也无法调用。
所以countUniques全局函数可以作为Array的扩展方法被重写如下:
extensionArraywhereElement:
Comparable{
funccountUniques()->Int{
letsorted=sort(<)
letinitial:
(Element?
Int)=(.None,0)
letreduced=sorted.reduce(initial){($1,$0.0==$1?
$0.1:
$0.1+1)}
returnreduced.1
}
}
注意:
只有元类型实现了Comparable协议新的方法才可以被使用。
例如,如果你在全部是UIView对象的数组中调用countUniques,编译器将会报错。
importUIKit
leta=[UIView(),UIView()]
a.countUniques()//compilererrorherebecauseUIViewdoesn'timplementComparable
问题5-Swift2.0orlater
下面一个函数的功能是计算两个double(optional)类型的数的相除的结果。
在执行除法之前,必须提前满足三个条件:
被除数必须包含nil值
除数必须为包含nil值
除数不能为零
funcdivide(dividend:
Double?
bydivisor:
Double?
)->Double?
{
ifdividend==.None{
return.None
}
ifdivisor==.None{
return.None
}
ifdivisor==0{
return.None
}
returndividend!
/divisor!
}
上面的函数可以正常使用,但是会存在两个问题: