苹果公司在2008年宣布并发布了iPhoneSDK2.0。随着这个事件引发了软件开发的又一次革命,诞生了一个新的开发者,称为iOS开发人员。
许多开发人员在此之前从未使用过Objective-C,这是苹果向他们发出的第一个挑战。尽管不熟悉的语法和手动内存管理,它已经成功,足以让应用商店与一万个应用程序。Apple不断改进Objective-C和每个版本,不断添加块和文字,简化内存管理与自动引用计数,以及许多其他功能精确定位现代编程语言。
在2010年,当iPhone刚刚3岁,编写本地应用程序的能力仍处于初期阶段,iPhone想出了4个版本的iPhoneOS,包括诱人的新特性,如多任务处理,快速应用切换,后台服务。苹果在iPhoneOS4SDK中以一个炸弹回来,并没有在软件中,而是在使用协议中。它说-
“应用程序必须最初用Objective-C,C和C++编写,只有使用C,C++和Objective-C编写的代码可以编译并直接与DocumentedAPI链接。”-“iPhoneOS4SDK”3.3.1节开发者协议
这个新的限制使开发者感到惊讶,但是我们听说史蒂夫·乔布斯(SteveJobs)声称它是防止使用跨平台工具的一个步骤。然而,Objective-C主要是为了应用程序生态系统的增长,但许多开发人员在2010年开始感到不满意,结果以其他编程语言编写iPhone应用程序的替代方法正在逐渐形成。
在过去6年里,与Objective-C合作之后,苹果决定在2014年在WWDC上摒弃另一个挑战。是的,再次,iOS开发人员将需要学习一种称为Swift的全新语言。
Swift-新的苹果语言
四年后的2010年,苹果公司向开发人员介绍了Swift的新语言。这证明了苹果准备接受Objective-C可能不是编写移动应用程序的最佳语言的真相。与Objective-C相比,Swift更是一种现代语言。如果是新的,那么你会有兴趣的了解如何从Objective-C到Swift。
你会注意到Swift和Objective-C之间的两个重要区别-
Swift不是C语言的严格超集-这表示Swift可以自由地使用未被使用的语法结构。这有助于在Swift中实现自定义运算符。
Swift不是动态类型的,而是静态键入-静态类型意味着您可以利用Haskell等先驱语言的优势。
Swift发射台
为了开始探索Swift,您需要从AppStore下载XCode6并开始实验。您可以访问苹果公司的Swift主页,以找到促进SwiftDevelopmentServices的最佳参考。为您的SwiftDevelopment创建一个游乐场,这里是一个指南-变量和常量在Swift中声明变量大量使用VAR关键字。
vary=1varz=“Hello”
我们选择两个变量“y”和“z”。Swift是一种安全的语言,它将从分配的值推导出变量类型。如果您希望使代码更易于阅读,您可以注释变量的类型。
vary:Inty=2
常数或多或少相似,但您使用LET而不是VAR来声明它们。常量的值在编译时不需要知道,但必须分配一次值。
让c1=1//编译时已知的常量varv=arc4random()letc2=v//仅在运行时才知道
由于他们的数字表明它们是不可变的,因此代码肯定会导致编译时错误。
让c=1c=3//错误
您也可以将其他类型声明为常数。在这个例子中,您可以发现以下代码一个数组被声明为常量,如果您尝试修改它,Swift编译器会触发一个错误:
其他类型也可以被声明为常数。例如,以下代码将数组声明为常量,如果您尝试修改任何元素,Swift编译器将报告错误:
vararr2=[4,5,6]arr2[0]=8print(arr2)//[8,5,6]让arr=[1,2,3]a[0]=5//error
可选项
您需要在声明变量和变量时初始化常量,您需要在使用之前对其进行初始化。您在Objective-C中找不到,但在Swift中找不到,因为可选值可以是一个值,否则为零,但是Objective-C不能为零。看看下面的代码,你会注意到,“x”同时分配了2015的可选值,这意味着Swift编译器知道“x”可能为零。
vars=“2015”varx=s.toInt()print(x)//可选(2015)
如果您在此代码中引入更改,并将值“xyz”分配给“s”,而不能转换为整数,则会注意到“x”为NIL。
vars=“abc”varx=s.toInt()print(x)//nil
“toInt()”函数的返回类型是“Int”,它用作可选的“Int”。现在让我们考虑一个“x”的标准函数:
varx=“2015”.toInt()print(x.successor())//错误
现在编译器发送信号是错误的,因为“x”是可选的,并且可能是NIL,我们必须先测试“x”,并确保后继函数调用实数而不是NIL值。
varx=“2014”.toInt()ifx!=nil{Print(x!.successor())//2015}
我们必须使用感叹号(!)附加它来解开“x”。当我们确定“x”包含一个值时,我们可以轻松访问它,否则我们可以得到运行时错误。我们还执行Swift调用为可选绑定的函数,将可选结果转换为非可选变量。
让x=“123”.toInt()如果让y=x{print(y)}
如果“x”具有要执行的值并将其分配给“y”,则代码将运行。我们不需要打开“y”,因为它不是可选的,因为“x”不是NIL.Look在Apple手册中阅读有关可选链接的更多详细信息。
字符串插值使用Objective-C时,通常使用“stringWithFormat:”方法
NSString*user=@“Gabriel”;intdays=3;NSString*s=[NSStringstringWithFormat:@“发布于%@(%d天前)”,user,days];
Swift有一个称为字符串插值的功能来执行相同的功能,但它更容易做和改进。
letuser=“Gabriel”letdays=3lets=“postedby\(user)\(days)ago”
您还可以使用以下表达式:
letwidth=2letheight=3lets=“具有边的正方形的面积\(宽度)和\(高度)是\(宽*高)”
阅读更多关于苹果的字符串插值。
函数从Objective-C,Swift中的函数定义是不同的。这是一个示例函数:
funcsomeFunction(s:String,i:Int)->Bool{…//code}
在Swift中,功能是一流的。这表示您可以为变量分配函数,将它们作为参数传递给其他函数,并使其返回类型:
funcstringLength(s:String)->Int{returncountElements(s)}funcstringValue(s:String)->Int{ifletx=s.toInt(){returnx}return0}funcdoSomething(f:String->Int,s:String)->Int{returnf(s).successor()}letf1=stringLengthletf2=stringValuedoSomething(f1,“123”)//4doSomething(f2,“123”)//124
再次,在Swift中,您会发现f1和f2的类型,尽管不可能明确定义它们。功能也可以返回其他功能:
让f1:String->Int=stringLength
funccompareGreaterThan(a:Int,b:Int)->Bool{returna>b}funccompareLessThan(a:Int,b:Int)->Bool{returna<b}funccomparator(greaterThan:Bool)->(Int,Int)->Bool{ifgreaterThan{returncompareGreaterThan}else{returncompareLessThan}}letf=comparator(true)println(f(5,9))
了解更多关于苹果图书馆功能的信息。
与Objective-C相比,Swift中的枚举枚举功能强大。斯威夫特很容易形成一个结构,他们可以有办法躺下来传递价值:
enumMobileDevice:String{caseiPhone=“iPhone”,Android=“Android”,WP8=“WindowsPhone8”,BB=“BlackBerry”funcname()->String{returnself.toRaw()}}letm=MobileDevice.Androidprint(m.name())//“Android”
与Objective-C相比,Swift中的枚举可以将字符串,字符或浮点分配为除整数外的每个成员的值。您可以找到方便的“toRaw()”方法,该方法返回分配给每个成员的值。枚举还包括参数-
枚举位置{caseAddress(street:String,city:String)caseLatLon(lat:Float,lon:Float)funcdescription()->String{switchself{caselet.Address(street,city)):returnstreet+,“+citycaselet.LatLon(lat,lon):return”(\(lat),\(lon))“}}}letloc1=Location.Address(街道:”20,ConnaughtPlace“,city:新德里“)letloc2=Location.LatLon(lat:28.6328,lon:77.2197)print(loc1.description())//”20,ConnaughtPlace,NewDelhi“print(loc2.description())//”(28.6328,77.2197)“
获取有关枚举的信息。
元组元组是一组几个值变成单个复合值。您可以发现元组中的值可以是任何类型的,并且不必彼此具有相同的类型。
让人=(“托马斯”,“哈代”)打印(person.0)//托马斯
您还可以在Tuple中命名各个元素:
让人=(第一:“托马斯”,最后:“哈迪”)打印(person.first)
元组是非常方便的选项,因为它们的返回类型可以返回多个值。
funcintDivision(a:Int,b:Int)->(商:Int,remaining:Int){return(a/b,a%b)}print(intDivision(11,3))//(3,2)letresult=intDivision(15,4)print(result.remainder)//3
Swift支持匹配switch语句的模式,您在Objective-C中找不到。
(0,0):println(“Numberiszero”)case(_,0):println(“Numberisreal”)default:println(““数字是虚构的”)}
在第二个例子中,我们不研究数字,所以我们使用_来匹配。您还可以在每种情况下检查其他条件。对于这种情况,我们需要将模式值绑定到常量:
letcomplex=(2.0,1.1)switchcomplex{case(0,0):println(“Numberiszero”)case(leta,0)其中a>0:println(“Numberisrealandpositive”)case假设a,0)其中a<0:println(“Numberisrealandnegative”)case(0,letb)其中b!=0:println(“Number只有虚部”)caselet(a,b):println(“Numberisimaginarywithdistance\(a*a+b*b)”)}
要了解更多关于元组的信息,请浏览AppleLibrary。
类Swift不需要为自定义的类或结构创建单独的接口和实现文件。在Swift中,您可以轻松地在单个文件中定义一个类或结构,并使该类或结构的外部接口可以自动使其他代码使用。
Swift中的类定义非常简单:
classbottle{varvolume:Int=600funcdescription()->String{return“此瓶子具有\(volume)ml”}}letb=Bottle()print(b.description())
您可以看到,声明和实现在同一个文件中。Swift不再使用标题和实现文件。我们给我们的例子添加一个标签:
classBottle{varvolume:Int=600varlabel:Stringfuncdescription()->String{return“这瓶\(标签)有\(volume)ml”}}
编译器将报告标签是非可选变量,并且在瓶初始化时不会保存任何值。
classBottle{varvolume:Int=600varlabel:Stringinit(label:String){self.label=label}funcdescription()->String{return“这个\(标签)}}
那么我们也可以使用可选类型的属性,我们不需要初始化它。在以下示例中,我们将volume设置为可选整数。
瓶瓶{varvolume:Int?varlabel:Stringinit(label:String){self.label=label}funcdescription()->String{ifself.volume!=nil{return“这个\(标签)的瓶子有\(volume!)ml”}else{return“\(label)的引导”}}}
结构Swift还具有像Objective-C这样的结构,但它更灵活。看看这个例子来了解Swift中的什么结构定义:
structSeat{varrow:intvarletter:Stringinit(row:Int,letter:String){self.row=rowself.letter=letter}funcdescription()->String{return“\(row)-\信)”}}
结构
Swift具有方法,属性和初始化以及一些协议的结构。类和结构之间的区别是类传递引用,但结构通过值。
letb=Bottle()print(b.description())//“b”bottlehas1000mlvarb2=bb.volume=750print(b2.description())//“b”and“b2”bottles有750毫升
如果我们尝试使用结构类似的情况,你会注意到它将通过值:
vars1=Seat(row:14,letter:“A”)vars2=s1s1.letter=“B”print(s1.description())//14-Bprint(s2.description())//14-一个
现在,当我们应该使用类或结构时,会出现一个问题。在Objective-C和C中,当我们需要对多个值进行分组并将其复制而不是引用时,我们使用结构例如,复数,2D或3D点等。然而,类通常是对象。在Swift中,我们已经看到,类和结构与其他语言密切相比,许多功能可以应用于类或结构。因此,Swift参考中使用的一般术语是“实例”,其适用于这两个中的任何一个。
您可以在AppleLibrary阅读关于swift的类和结构。
查找Objective-C和Swift的兼容性
一。iOS与OSX共享背景,并且都与1989年发布的NeXTSTEP操作系统挂钩。后来的Objective-C和许多核心库中的文档追溯到这些原始实现中。Swift没有根源,但是将来它将不得不接口Objective-C。
乙。Swift已经与Objective-C进行了无痛的交互,但并不表示无痛的过程。苹果提供了一个有用的指南,解释了如何从Swift调用Objective-C代码,反之亦然。您还会遇到一些重要的阻抗不匹配,并且必须留意它们。
Ç。这里可能会发现最明显的不匹配与头文件有关。在C中有其根源的Objective-C仍然需要声明来调用它们。当你可以到图书馆,你会发现在图书馆的头文件中找到的声明。至于Swift,他们不使用头文件。如果要从Objective-C调用Swift代码,则需要创建桥接头。从概念上看,这似乎并不复杂,但这可能是一项艰巨的任务。
ð。Swift和Objective-C之间的另一组并发症在于它们的类型系统。Swift将其他现代语言的概念从NIL的概念中消失。在其所在的地方,Swift的可选类型。例如,只有在已经存在的情况下才能打开文件的方法在Swift中具有“File?”的返回类型。通过调整所有类型可选的地方,Swift编译器可以有效地使得可能遇到可怕的“空指针错误”。Objective-C不保证不返回零。相反,Swift带有特殊类别的类型,称为隐式解包可选常用于调用Objective-C代码。这些类型在Swift中被视为可选项,以及存在检查所需的开销。您可以交替使用它,并且可以使用与非可选类型相同的内容,但是如果Objective-C返回,则“nil”将导致运行时错误。因此,有一些Swift的编译时安全保障。
Ë。Swift和Objective-C之间的另一个微妙的不一致之处就是消除了Apple的两种编程语言中封装下的对象和类。Objective-C由于它们的动态特性,利用动态调度来调用对象的方法(通过“objc_msgSend”)。Swift肯定会使用动态调度,但由于它是静态类型的,它还可以选择使用“vtable”来存储每个调用方法的函数指针。Swift使用的两个机制取决于多个因素PlaneOldSwiftObjects将使用“vtable”机制,除非类中的类或方法使用“@objc”Swift属性进行注释。
˚F。有机会继承Objective-C类的Swift类将使用动态调度来进行继承的方法。但是,子类引入的任何新方法是不可能的(您可以强制使用“@objc”属性进行动态调度)。不用说Swift代码可以使用Swift类,但是如果注释,Objective-C代码只能使用Swift对象和方法。
Swift在苹果实验室每天都在发展。你会遇到一些新的东西来了解Swift。这些包括泛型,与Objective-C库的交互,关闭,可选链接和操作符重载。在一篇文章中不可能讨论所有这些文章,以彻底地描述一种新的语言。
那么这个快速阅读将帮助许多开发人员了解Objective-C,特别是对于那些还没有管理时间学习Swift语言的细节的人来说可以顺利进行。