Swift Tips
转载:转自猫神100个Swift必备Tips,onevcatSelector
-(void)callMe{//...}-(void)callMeWithParam:(id)obj{//...}SELsomeMethod=@selector(callMe);SELanotherMethod=@selector(callMeWithParam:);// 或者也可以使用 NSSelectorFromString// SEL someMethod = NSSelectorFromString(@"callMe");// SEL anotherMethod = NSSelectorFromString(@"callMeWithParam:");
一般为了方便,很多人会选择使用 在 Swift 中没有
funccallMe(){//...}funccallMeWithParam(obj:AnyObject!){//...}letsomeMethod=Selector("callMe")letanotherMethod=Selector("callMeWithParam:")
和 Objective-C 时一样,记得在
functurnByAngle(theAngle:Int,speed:Float){//...}letmethod=Selector("turnByAngle:speed:")
另外,因为 最后需要注意的是,selector 其实是 Objective-C runtime 的概念,如果你的 selector 对应的方法只在 Swift 中可见的话 (也就是说它是一个 Swift 中的 private 方法),在调用这个 selector 时你会遇到一个 unrecognized selector 错误:
正确的做法是在
@objcprivatefunccallMe(){//...}NSTimer.scheduledTimerWithTimeInterval(1,repeats:true)
另外,如果方法的第一个参数有外部变量的话,在通过字符串生成
funcaMethod(externalparamName:AnyObject!){...}
想获取对应的获取
lets=Selector("aMethodWithExternal:")
Sequence Swift 的
// 先定义一个实现了 GeneratorType protocol 的类型// GeneratorType 需要指定一个 typealias Element// 以及提供一个返回 Element? 的方法 next()classReverseGenerator:GeneratorType{typealiasElement=Intvarcounter:Elementinit<T>(array:[T]){self.counter=array.count-1}init(start:Int){self.counter=start}funcnext()->Element?{returnself.counter<0?nil:counter--}}// 然后我们来定义 SequenceType// 和 GeneratorType 很类似,不过换成指定一个 typealias Generator// 以及提供一个返回 Generator? 的方法 generate()structReverseSequence<T>:SequenceType{vararray:[T]init(array:[T]){self.array=array}typealiasGenerator=ReverseGeneratorfuncgenerate()->Generator{returnReverseGenerator(array:array)}}letarr=[0,1,2,3,4]// 对 SequenceType 可以使用 for...in 来循环访问foriinReverseSequence(array:arr){println("Index (i) is (arr[i])")}
输出为
Index4is4Index3is3Index2is2Index1is1Index0is0
如果我们想要深究
varg=array.generate()whileletobj=g.next(){println(obj)}
顺便你可以免费得到的收益是你可以使用像 @autoclosure 和 ?? Apple 为了推广和介绍 Swift,破天荒地为这门语言开设了一个博客(当然我觉着是因为 Swift 坑太多需要一个地方来集中解释)。其中有一篇提到了一个叫做 比如我们有一个方法接受一个闭包,当闭包执行的结果为
funclogIfTrue(predicate:()->Bool){ifpredicate(){println("True")}}
在调用的时候,我们需要写这样的代码
logIfTrue({return2>1})
当然,在 Swift 中对闭包的用法可以进行一些简化,在这种情况下我们可以省略掉
logIfTrue({2>1})
还可以更近一步,因为这个闭包是最后一个参数,所以可以使用尾随闭包 (trailing closure) 的方式把大括号拿出来,然后省略括号,变成:
logIfTrue{2>1}
但是不管那种方式,要么是书写起来十分麻烦,要么是表达上不太清晰,看起来都让人生气。于是
funclogIfTrue(@autoclosurepredicate:()->Bool){ifpredicate(){println("True")}}
这时候我们就可以直接写:
logIfTrue(2>1)
来进行调用了,Swift 将会吧 在 Swift 中,有一个非常有用的操作符,可以用来快速地对
varlevel:Int?varstartLevel=1varcurrentLevel=level??startLevel
在这个例子中我们没有设置过
func??<T>(optional:T?,@autoclosuredefaultValue:()->T?)->T?func??<T>(optional:T?,@autoclosuredefaultValue:()->T)->T
在这里我们的输入满足的是后者,虽然表面上看
func??<T>(optional:T?,@autoclosuredefaultValue:()->T)->T{switchoptional{case.Some(letvalue):returnvaluecase.None:returndefaultValue()}}
可能你会有疑问,为什么这里要使用 就这样,我们可以巧妙地绕过条件判断和强制转换,以很优雅的写法处理对 Optional Chaining使用 Optional Chaining 可以让我们摆脱很多不必要的判断和取值,但是在使用的时候需要小心陷阱。 因为 Optional Chaining 是随时都可能提前返回
classToy{letname:Stringinit(name:String){self.name=name}}classPet{vartoy:Toy?}classChild{varpet:Pet?}
在实际使用中,我们想要知道小明的宠物的玩具的名字的时候,可以通过下面的 Optional Chaining 拿到:
lettoyName=xiaoming.pet?.toy?.name
注意虽然我们最后访问的是 在实际的使用中,我们大多数情况下可能更希望使用 Optional Binding 来直接取值的这样的代码:
iflettoyName=xiaoming.pet?.toy?.name{// 太好了,小明既有宠物,而且宠物还正好有个玩具}
可能单独拿出来看会很清楚,但是只要稍微和其他特性结合一下,事情就会变得复杂起来。来看看下面的例子:
extensionToy{funcplay(){//...}}
我们为
xiaoming.pet?.toy?.play()
除了小明也许我们还有小红小李小张等等..在这种时候我们会想要把这一串调用抽象出来,做一个闭包方便使用。传入一个 你会发现这么表意清晰的代码居然无法编译! 问题在于对于
letplayClosure={(child:Child)->()?inchild.pet?.toy?.play()}
这样调用的返回将是一个
ifletresult:()=playClosure(xiaoming){println("好开心~")}else{println("没有玩具可以玩 :(")}
func 的参数修饰在声明一个 Swift 的方法的时候,我们一般不去指定参数前面的修饰符,而是直接声明参数:
funcincrementor(variable:Int)->Int{returnvariable+1}
这个方法接受一个 有些同学在大学的 C 程序设计里可能学过像 残念..编译错误。为什么在 Swift 里这样都不行呢?答案是因为 Swift 其实是一门讨厌变化的语言。所有有可能的地方,都被默认认为是不可变的,也就是用
funcincrementor(letvariable:Int)->Int{return++variable}
funcincrementor(varvariable:Int)->Int{return++variable}
现在我们的+1器又可以正确工作了:
varluckyNumber=7letnewNumber=incrementor(luckyNumber)// newNumber = 8println(luckyNumber)// luckyNumber 还是 7
正如上面的例子,我们将参数写作
funcincrementor(inoutvariable:Int){++variable}
因为在函数内部就更改了值,所以也不需要返回了。调用也要改变为相应的形式,在前面加上
varluckyNumber=7incrementor(&luckyNumber)println(luckyNumber)// luckyNumber = 8
最后,要注意的是参数的修饰是具有传递限制的,就是说对于跨越层级的调用,我们需要保证同一参数的修饰是统一的。举个例子,比如我们想扩展一下上面的方法,实现一个可以累加任意数字的+N器的话,可以写成这样:
funcmakeIncrementor(addNumber:Int)->((inoutInt)->()){funcincrementor(inoutvariable:Int)->(){variable+=addNumber;}returnincrementor;}
外层的 外层的 |