Swift带来了许多非常酷的特性,以至于很难回到Objective-C。主要特征是安全性,但这也被视为额外的副作用。带类型接口的强类型Swift具有强类型,这意味着除非您要求,否则Swift不会为您在类型之间进行转换。因此,例如,您不能将Int分配给Double。您必须先转换类型:leti:Int=42letd:Double=Double(i)或者您必须使用转换Int类型的方法扩展Double类:extensionDouble{func__convert(i:Int)->Double{returnDouble(i)}}letanother_d:Double=i强类型对安全性非常非常好。但它也会变得有点令人生畏,有点像编写脚本语言,如果它不为您向类型接口添加大量类型信息的话。letary=["Hello","world"]//NOTE:'ary'isoftypeString[]orArrayforsinary{//NOTE:'s'isoftypeStringprint(s+"")}如果你想创建一个包含很多的字符串类型(没有共同的祖先),你应该使用枚举(它可以包含值,见下文)。如果你想让它包含所有的值,你可以使用Any类型。如果您希望它包含任何Objective-C类型,请使用AnyObject类型。请注意,类型接口在声明函数时不会为您添加类型。您必须明确说明所声明函数的类型。BlocksSwift中的Blocks与Objective-C中的Blocks非常相似,但有两个不同之处:类型推断和避免weakifydance。使用类型推断,您不必在每次编写块时都包含完整的类型信息:sort([2,1,3],{(a:Int,b:Int)->Boolinreturna())?//注意:TheoptionalcallbacktakesanIntdeinit{//注意:Thisislike-deallocinObjective-Cprintln("Deinit")}}varobj=CallbackTest()obj.callback={[unownedobj]//注意:如果没有这个,deinit()将永远不会被调用!ainobj.i=a}请注意Optional(如上面的回调)在介绍文章中介绍。请参阅ARC章节以了解有关Swift中的ARC的更多信息。强大的枚举Swift中的枚举是对Objective-C的巨大改进。FixEnumsApplehasalwaysadvocatedthedisplayofthesizeoftheenumerationtype,butitwasmessedupbyObjective-C//ApplerecommendedenumdefinitioninObjective-CtypedefNS_ENUM(NSInteger,UIViewAnimationCurve){UIViewAnimationCurveEaseInOut,UIViewAnimationCurveEaseIn,UIViewAnimationCurveEaseOut,UIViewAnimationCurveLinear}.fin/PreviousApplerecommend/enumvaluesandtheUIViewAnimationCurvetype.typedefenum{UIViewAnimationCurveEaseInOut,UIViewAnimationCurveEaseIn,UIViewAnimationCurveEaseOut,UIViewAnimationCurveLinear};typedefNSIntegerUIViewAnimationCurve;//TraditionalenumdefinitioninObjective-C.Noexplicitfixedsize.typedefenum{UIViewAnimationCurveEaseInOut,UIViewAnimationCurveEaseIn,UIViewAnimationCurveEaseOut,UIViewAnimationCurveLinear}UIViewAnimationCurve;Swift中的修复:enumUIViewAnimationCurve:Int{caseEaseInOutcaseEaseIncaseEaseOutcaseLinear}拓展EnumsEnums在Swiftgoesone更进一步,仅作为独立的选项列表。您可以添加方法(和计算属性):enumUIViewAnimationCurve:Int{caseEaseInOutcaseEaseIncaseEaseOutcaseLinearfunctypeName()->String{return"UIViewAnimationCurve"}}使用类型扩展,您可以将任何您想要的方法添加到枚举中:extensionUIViewAnimationCurve{funcdescription()->String{switchself{caseEaseInOut:return"EaseInOut"caseEaseIn:return"EaseIn"caseEaseOut:return"EaseOut"caseLinear:return"Linear"}}}#p#AddvaluetoEnumsSwift中的枚举允许进一步每个独立的选项都有对应的值:enumShape{caseDotcaseCircle(radius:Double)//Requireargumentname!caseSquare(Double)caseRectangle(width:Double,height:Double)//Requireargumentnames!funcarea()->Double{switchself{caseDot:return0caseCircle(letr)://Assigntheassociatedvaluetotheconstant'r'returnπ*r*rcaseSquare(letl):returnl*lcaseRectangle(letw,leth):returnw*h}}}varshape=Shape.Dotshape=.Square(2)shape=.Rectangle(width:3,height:4))//Argumentnamesrequiredshape.area()你可以把它当作安全联合体pe如果你喜欢。或者只是使用枚举应该做什么。Enumerations文章详细介绍了Apple对此的看法。SwiftSwitch语句可以看到,Swift中的switch语句有很多优化。隐式失败行为已更改为显式:var(i,j)=(4,-1)//Assign(andcreate)twovariablessimultaneouslyswitchi{case1:j=1case2,3://Thecaseforboth2and3j=2case4:j=4fallthroughcase5:j++default:j=Int.max//TheSwiftversionofINT_MAX}如前所述,Switch语句可以访问枚举的关联值,但它可以做的更多:vartuple:(Int,Int)//DidImentionthatSwifthastuples?:-)varresult:Stringtuple=(1,3)switchtuple{case(letx,lety)whereex>y:result="Larger"case(letx,lety)whereexBool{returnstr.hasPrefix(pattern)}vars="Carbon"开关{case"J":s="Highcaffeine"case"C":s="Nocaffeine"default:()}您可以从条件语句一文中了解有关switch语句的更多信息。类和结构与C++类似,Swift的类和结构乍一看也一样:classApple{varcolor="green"//Propertydeclarationinit(){}//Defaultinitializerinit(_color:String){//'_'meansnoargumentnameself。color=color}funcdescription()->String{return"appleofcolor\(color)"}funcenripen(){color="red"}}structOrange{varcolor="green"init(){}init(_color:String){self.color=color}funcdescription()->String{return"orangeofcolor\(color)"}mutatingfuncenripen(){//注意:'mutating'isrequiredcolor="orange"}}varapple1=Apple()varapple2=apple1//注意:Thisreferencesthesameobject!apple1.enripen()apple2.description()//Result:"appleofcolorred"varorange1=Orange()varorange2=orange1//注意:Thismakesacopy!orange1.enripen()orange2.description()//Result:"orangeofcolorgreen"主要区别在于类是引用类型(如块),而结构是数字类型(如枚举)。因此,两个变量可以指向相同的(类的)对象,而将结构分配给另一个变量必须执行结构的(慢速)副本。关键字“mutating”告诉调用者不能在常量结构上调用enripen()方法。改变对类对象的常量引用没有问题。Swift中的大多数内置类型实际上都是结构体。甚至Int类型也是。点击Cmd可以看到内置类型的声明,比如Int类型的Swift(或Playground)源码。数组和字典类型也是结构,但数组在某些方面表现得像引用类型:对数组的赋值不会复制每个元素,只要元素数量保持不变,您实际上可以更新常量数组。letarray1=[1,2,3]letarray2=array1//Acopy,butreferencesthesameelements!array1[1]=5//Legal,asitdoesn'tmodifythestructbutareferencedelementarray2//Result:[1,5,3]在Apple的文档中,可以阅读更多关于集合类型。#p#对象的生命周期类和结构的另一个区别是类可以被子类化。对象和结构都可以扩展和实现协议,但只有类可以从其他类继承。classPineapple:Apple{init(color:String){super.init(color)}convenienceinit(){self.init("green")}convenienceinit(ripe:Bool){self.init()ifripe{color="yellow"}else{color="green"}}deinit{println("Pineappledown")}overridefuncdescription()->String{return"pine"+super.description()}overridedefuncenripen(){color="yellow"}}像你可以看到,Swift为学习继承增加了一点乐趣。对于初学者,您需要明确重写父类中方法的意图。如果你想防止子类覆盖某些东西,你可以在单个声明或整个类前面加上@final属性。阅读Apple的文档以了解更多信息。初始化Swift对象分两步初始化:首先对象必须有效,然后它可以被替换。classChildShoe{varsize:Double//Uninitializedpropertiesarenotallowedunlesstakencareofinit()init(foot_size:Double){size=foot_size//FirstmaketheobjectvalidaddGrowthCompensation()}funcaddGrowthCompensation(){size++}}要使对象有效,必须调用a指定的init()方法超级类。类可以同时具有特定的和方便的(用关键字'convenience'标记)初始化器。便利初始化器调用同一类中的其他初始化器(最终是指定初始化器),指定初始化器调用超类初始化器。如果您将构造器添加到所有超类的指定构造器,您的类也会自动继承所有便利构造器。如果您不添加任何指定的初始值设定项,您的类将继承超类的所有(指定和方便的)初始值设定项。请参阅初始化以进一步阅读。对于类之间的转换,尤其是向下转型,可以使用“is”、“as?”。和“as”关键字:letapple:Apple=Pineapple()lexotic:Bool=appleisPineappleletpineappleOption:Pineapple?=appleas?Pineappleletpineapple:Pineapple=appleasPineapple//NOTE:Throwsifnot!ifletobj=appleas?Pineapple{//Ifexecuted,'obj'isaPineapple"sweet"}有关更多信息,请参阅类型转换一章。泛型是Swift的一项额外功能。它们看起来有点像C++中的模板,但具有更强的类型并且更简单(更易于使用,功能更弱)。01//MarkbothIntandDoubleasbeingconvertibletoaDoubleusingthe'+'prefix02protocolDoubleConvertible{03@prefixfunc+(v:Self)->Double04}05@prefixfunc+(v:Int)->Double{returnDouble(v)}06extensionDouble:DoubleConvertible{}07extensionInt:Double08/Convertible{}/NOTE:RepeatthisforallInt*,UInt*,andtheFloattype0910//Thetraitsofafageneralizedpoint11protocolPointTraits{12typealiasT13classvardimensions:Int{get}14funcgetCoordinate(dimension:Int)->T15}1617//广义毕达哥拉斯18structPythagoras{19staticfuncapply(a:P1,b:P2,dimensions:Int)->Double{20ifdimensions==0{21return022}23letd:Double=+a.getCoordinate(dimensions-1)-+b.getCoordinate(dimensions-1)//注意:'+'toconverttoDouble24returnd*d+apply(a,b:b,dimensions:dimensions-1)25}26staticfuncapply(a:P1,b:P2)->Double{27letdimensions=P1.dimensions28assert(P2.dimensions==dimensions)29returnapply(a,b:b,dimensions:dimensions)30}31};3233importfuncFoundation.sqrt//注意:你可以importatypealias,struct,class,enum,protocol,var,orfunconly3435funcdistance(a:P1,b:P2)->Double{36assert(P1.dimensions==P2.dimensions)37returnsqrt(Pythagoras.apply(a,b:b));38}3940//Ageneralized2Dpoint41structPoint2D:PointTraits{42staticvardimensions:Int{return2}43varx:Number,y:Number44funcgetCoordinate(dimension:Int)->Number{returndimension==0?x:y}//注意:ThetypealiasTisinferred45}46leta=Point2D(x:1.0,y:2.0)47letb=Point2D(x:5,y:5)48Pythagoras.apply(a,b:b)//注意:方法需要参数名称,除了第一个49距离(a,b)//注意:函数不需要参数名称5051//UIColor52extensionUIColor:PointTraits{53classvardimensions:Int{return4}54funcgetCoordinate(dimension:Int)->双{55varred:CGFloat=0,绿色:CGFloat=0,蓝色:CGFloat=0,alpha:CGFloat=056getRed(&red,green:&green,blue:&blue,alpha:&alpha)57switchdimension{58case0:returnred59case1:returngreen60case2:returnblue61default:returnalpha62}63}64}65distance(UIColor.redColor(),UIColor.orangeColor())灵感来自Boost中的设计原理。几何C++库Swift中的泛型功能并没有那么强大,但是相比C++中的泛型,它可以让源码的可读性更强。Swift中的泛型是按类型参数化的。每个参数类型都需要实现特定的协议或从特定的基类继承。在声明了参数类型之后,有一个可选的“where”项,可以用来为这个类型(或者它们的内部类型,比如上面PointTraits协议中的别名'T')添加额外的要求。这个“哪里”也可以要求两种类型相等。苹果有一个更完整的泛型章节。选择Swift现在你已经准备好查看各种源代码,甚至可以编写你自己的:-)在将自己留在一个新的Swift未知领域之前,我有一些最后的建议:ApplerecommendsyouuseIntforall整数类型,即使您之前使用过无符号数字。“仅当您确实需要与平台的本机大小相同大小的无符号整数时才使用UInt。”如果你想知道@private和al在哪里。添加。如果您创建了一个模块,您可以按住Cmd键并单击您的模块名称以查看您的模块自动生成的Swift标头。Swift模块实际上是命名空间,所以像CF、NS、UI等所有东西都加上前缀。在创建第三方库时并不是绝对必要的。享受使用Swift的乐趣!