其中许多开发人员在此之前从未使用过Objective-C,这是Apple向他们吹嘘的第一个挑战。尽管语法和手动内存管理不熟悉,它还是成功地为App Store填充了上万个应用程序。苹果一直在改进Objective-C并在每个版本中不断改进,不断添加块和文字,通过自动引用计数简化了内存管理,并提供了许多其他功能来指明现代编程语言。
在2010年,当时iPhone才3岁,当时尚无法编写本机应用程序,因此iPhone推出了第4版iPhone OS,其中包括诱人的新功能,如多任务处理,快速的应用程序切换和后台服务。苹果公司在iPhone OS 4 SDK中带来了重磅炸弹,它不在软件中,而在使用协议中。它说–
“应用程序最初必须使用Objective-C,C和C ++编写,并且只有用C,C ++和Objective-C编写的代码才可以编译并直接链接到Documented API。” – iPhone OS 4 SDK开发人员协议的3.3.1节。
这一新的限制使开发人员感到惊讶,但我们听到史蒂夫·乔布斯(Steve Jobs)声称这是防止使用跨平台工具的一步。但是,Objective-C在很大程度上促进了应用程序生态系统的发展,但由于用其他编程语言编写iPhone应用程序的替代方法的兴起,许多开发人员在2010年开始感到不满意。
在与Objective-C一起工作了6年之后,苹果决定于2014年在WWDC上放弃另一个挑战。是的,iOS开发人员将再次需要学习一种全新的语言,称为Swift。
迅捷–新的Apple语言
2010年后的四年,苹果公司向开发人员介绍了其新语言Swift。事实证明,苹果已经准备好接受一个事实,那就是Objective-C可能不是编写移动应用程序的最佳语言。与Objective-C相比,Swift更现代。如果不熟悉Swift,那么您将非常有兴趣了解如何从Objective-C转到Swift。
您会注意到Swift和Objective-C之间的两个重要区别–
Swift不是C语言的严格超集-这表示Swift可以自由使用未使用的语法构造。这有助于在Swift中实现自定义运算符。
Swift不是动态类型,而是静态类型–静态类型意味着您可以利用Haskell等开创性语言的优势。
迅捷发射台
为了开始探索Swift,您需要从App Store下载XCode 6并开始实验。您可以转到Apple的Swift主页,找到促进Swift开发服务的最佳参考。要为您的Swift开发创建一个操场,这里是一个指南-
变量和常量
在Swift中声明变量非常使用VAR关键字。
var y = 1
var z =“你好”
我们选择两个变量“ y”和“ z”。Swift是一种安全的语言,它将根据分配的值推断出变量类型。如果希望使代码更具可读性,则可以注释变量的类型。
var y:Int
y = 2
常量或多或少相似,但是您使用LET而不是VAR声明它们。常量的值不需要在编译时就知道,但是必须将其赋值一次。
let c1 = 1 //编译时已知的常量
var v = arc4random()
let c2 = v //仅在运行时已知的常量
正如它们的数量所暗示的那样,它们是不可变的,因此遵循代码肯定会导致编译时错误。
令c = 1
c = 3 //错误
您还可以将其他类型声明为常量。在此示例中,您可以发现以下代码将数组声明为常量,如果尝试对其进行修改,则Swift编译器将引发错误:
其他类型也可以声明为常量。例如,以下代码将数组声明为常量,并且如果您尝试修改任何元素,则Swift编译器将报告错误:
var arr2 = [4,5,6]
arr2 [0] = 8
print(arr2)// [8,5,6]
let arr = [1,2,3]
a [0] = 5 //错误
选装件
声明常量时需要对其进行初始化,而对于变量,则需要在使用前对其进行初始化。您无法在Objective-C中找到它,但是在Swift中可以找到它,因为可选值可以有一个值或为nil,但是Objective-C不能为nil等效。查看以下代码,您会注意到“ x”同时分配了一个可选值2015,这意味着Swift编译器意识到“ x”可能为nil。
var s =“ 2015”
var x = s.toInt()
print(x)//可选(2015年)
如果在此代码中进行更改,并将值“ xyz”分配给无法转换为整数的“ s”,则会注意到“ x”变为NIL。
var s =“ abc”
var x = s.toInt()
print(x)//无
函数“ toInt()”的返回类型为“ Int?” 它用作可选的“ Int”。现在让我们考虑“ x”上的标准函数:
var x =“ 2015” .toInt()
print(x.successor())//错误
现在,编译器将错误发送信号,因为“ x”是可选的,并且可能为NIL,我们必须先测试“ x”,并确保后继函数调用的是实数而不是NIL值。
var x =“ 2014” .toInt()
如果x!= nil
{
Print(x!.successor())// 2015
}
我们必须通过在其前面加上感叹号(!)来拆开“ x”。当我们确定“ x”包含一个值时,我们可以轻松地访问它,否则我们将获得运行时错误。我们还执行Swift称为可选绑定的函数,将可选转换为非可选变量。
如果让y = x
{
print(y)
},则让x =“ 123” .toInt()
如果“ x”具有要执行的值,则代码将运行并将其分配给“ y”。我们不需要为此拆开“ y”,因为它不是可选的,因为“ x”不是NIL。请参阅Apple手册以了解有关Optional Chaining的更多详细信息。
字符串插值
使用Objective-C时,通常使用“ stringWithFormat:”方法进行
NSString * user = @“ Gabriel”;
整数天= 3;
NSString * s = [NSString stringWithFormat:@”%@(%d天前)发布,”用户,天];
Swift具有一个称为字符串插值的功能,可以执行相同的功能,但是更容易实现和完善。
let user =“ Gabriel”
let days = 3let s =“由\(用户)\(天)前发布”
您还可以使用以下表达式:
let width = 2
let height = 3
let s =“带有边\(width)和\(height)的正方形的面积为\(width * height)”
在Apple上了解有关字符串插值的更多信息。
函数
在Objective-C中,Swift中的函数定义不同。这是一个示例函数:
func someFunction(s:String,i:Int)-> Bool
{
…//代码}
在Swift中,这些函数是一流的类型。这表明您可以将函数分配给变量,将它们作为参数传递给其他函数,并使它们返回类型:
func stringLength(s:String)-> Int
{
返回countElements(s)
}
func stringValue(s:String)-> Int
{
如果让x = s.toInt()
{
return x
}
return 0
}
func doSomething(f:String -> Int,s:String)-> Int
{
return f(s).successor()
}
让f1 = stringLength
让f2 = stringValue
doSomething(f1,“ 123”)// 4
doSomething(f2,“ 123”)/ / 124
同样,在Swift中,您会找到f1和f2的类型,尽管不可能显式定义它们。
函数还可以返回其他函数:
让f1:String-> Int = stringLength
func compareGreaterThan(a:Int,b:Int)-> Bool
{
返回a> b
}
func compareLessThan(a:Int,b:Int)-> Bool
{
返回a
}
func比较器(greaterThan:Bool)->( Int,Int)-> Bool
{
如果大于大于
{
返回compareGreaterThan
}
否则
{
返回compareLessThan
}
}
令f =比较器(true)
println(f(5,9 ))
在Apple的Library中了解有关功能的更多信息。
枚举
与Objective-C相比,Swift中的枚举功能强大。Swift很容易形成一个结构,它们可以有躺下并传递值的方法:
枚举MobileDevice:字符串
{
case iPhone =“ iPhone”,Android =“ Android”,WP8 =“ Windows Phone8”,BB =“ BlackBerry”
func name()->字符串
{
return self.toRaw()
}
}
let m = MobileDevice .Android
print(m.name())//“ Android”
与Objective-C相比,Swift中的枚举可以为每个成员分配字符串,字符或浮点数作为值(整数除外)。您可以找到方便的“ toRaw()”方法,该方法返回分配给每个成员的值。枚举还包括参数–
枚举位置
{
案例地址(街道:字符串,城市:字符串)
案例LatLon(lat:Float,lon:Float)
func description()->字符串
{
切换自我
{
案例let。地址(街道,城市):
返回街道+“ ,” +城市
案例let .LatLon(lat,lon):
返回“((\(lat),\(lon))””
}
}
}}
loc1 = Location.Address(街道:“ 20,康诺特广场”,城市:“新德里”)
let loc2 = Location.LatLon(lat:28.6328,lon:77.2197)
print(loc1.description())//“新
德里康诺特广场20号” print(loc2.description())//“( 28.6328,77.2197)”
在此处获取有关枚举的信息。
元
组元组是由多个值组成的一组,变成单个复合值。您会发现元组中的值可以是任何类型,而不必彼此相同。
let person =(“ Thomas”,“ Hardy”)print(person.0)//托马斯
您还可以在Tuple中命名各个元素:
let person =(第一个:“ Thomas”,最后一个:“ Hardy”)print(person.first)
元组是非常方便的选项,因为它们的返回类型用于返回多个值的函数。
func intDivision(a:Int,b:Int)->(商:Int,余数:Int)
{
return(a / b,a%b)
}
print(intDivision(11,3))//(3,2)
let result = intDivision(15,4)
print(result.remainder)// 3
Swift支持与switch语句匹配的模式,您无法在Objective-C中找到该模式。
let complex =(2.0,1.1)//实部和虚部切换complex
{
case(0,0):
println(“ Number is zero”)
case(_,0):
println(“ Number is real”)
默认值:
println( “数字是假想的”)
}
在第二个示例中,我们不考虑数字,因此我们使用_进行匹配。您也可以在每种情况下检查其他条件。对于该实例,我们需要将模式值绑定到常量:
让complex =(2.0,1.1)
切换复数
{
case(0,0):
println(“数字为零”)
case(let a,0)其中a> 0:
println(“ Number为实数和正数”)
case(设a,0)其中a <0:
println(“数字是实数和负数”)
情况(0,令b)其中b!= 0:
println(“数字只有虚部”)
情况(a,b) :
println(“数字是假想的,距离为\(a * a + b * b)”)
}
要了解有关Tuple的更多信息,请浏览Apple Library。
类
Swift不需要为定制的类或结构创建单独的接口和实现文件。在Swift中,您可以轻松地在单个文件中定义类或结构,并且该类或结构的外部接口会自动提供给其他代码使用。
在Swift中,类定义非常简单:
类Bottle
{
var volume:Int = 600func description()-> String
{
return“此瓶子有\(volume)ml”
}
}
let b = Bottle()
pri
nt(b.description())
如您所见,声明和实现位于同一文件中。Swift不再使用头文件和实现文件。让我们在示例中添加标签:
类Bottle
{
var volume:Int = 600
var label:String
func description()-> String
{
return“这瓶\(label)具有\(volume)ml”
}
}
编译器将报告标签为非可选变量,并且在Bottle初始化时将不保存任何值。
class Bottle
{
var volume:Int = 600
var label:String
init(label:String)
{
self.label = label}
func description()-> String
{
return“这瓶\(label)具有\(volume)ml”
}
}
好吧,我们也可以对属性使用可选类型,而无需初始化它。在以下示例中,我们将volume作为可选整数。
类别Bottle {
var volume:Int?
var label:String
init(label:String)
{
self.label = label
}
func description()-> String
{
如果self.volume!= nil
{
返回“这瓶\(label)具有\(volume!)ml”
}
else
{
返回“ \(标签)的bootle””
}
}
}
结构
Swift还具有类似于Objective-C的结构,但是它更加灵活。查看以下示例,以了解Swift中定义的结构:
struct Seat
{
var row:Int
var letter:String
init(row:Int,letter:String)
{
self.row = row
self.letter = letter
}
func description()-> String
{
return“ \(row)-\(字母)”
}
}
结构体
Swift的结构包含方法,属性和初始化器以及一些协议。类和结构之间的区别在于,类通过引用传递,但结构按值传递。
让b = Bottle()
print(b.description())//“ b”瓶具有1000毫升
var b2 = b
b.volume = 750
print(b2.description())//“ b”和“ b2”瓶750毫升
如果我们在结构上尝试类似的情况,您会注意到它将通过值传递:
var s1 = Seat(第14行,字母:“ A”)
var s2 = s1
s1.letter =“ B”
print(s1.description())// 14-B
print(s2.description())// 14 -一种
现在,当我们应该使用类或结构时出现一个问题。在Objective-C和C中,当需要对多个值进行分组并复制而不是引用时,我们使用结构。例如,复数,2D或3D点等。但是,类通常是对象。在Swift中,我们已经看到类和结构与其他语言的比较紧密,许多功能可以应用于类或结构。结果,在Swift参考中使用的通用术语是“实例”,这在这两个实例中都适用。
您可以在Apple Library上了解Swift的类和结构。
找到Objective-C和Swift的兼容性
一。iOS与OS X具有相同的背景,并且都与1989年发布的NeXTSTEP OS保持联系。后者是用Objective-C编写的,并且许多核心库都源于这些原始实现。Swift没有其根源,但将来它将必须与Objective-C交互。
乙。Swift已经实现了与Objective-C的轻松交互,但这并不表示该过程是轻松的。苹果已经获得了一份有用的指南,该指南解释了如何从Swift调用Objective-C代码,反之亦然。您还将遇到一些重要的阻抗失配,并且必须时刻注意它们。
Ç。您可能在这里发现的最明显的不匹配与头文件有关。植根于C的Objective-C仍然需要其功能来声明而不是调用它们。当您可以访问库时,您会在库的头文件中找到声明。至于Swift,它们不使用头文件。如果要从Objective-C调用Swift代码,则需要创建桥接标头。从概念上讲,这似乎并不复杂,但这可能是一项艰巨的任务。
d。Swift和Objective-C之间的另一套复杂之处在于它们的类型系统。斯威夫特(Swift)从其他现代语言中吸取了各种概念,从而消除了NIL的概念。Swift的可选类型代替了它。例如,仅当文件已经存在时才用于打开文件的方法的返回类型为“文件?”。在Swift中。通过在所有类型都是可选的地方添加内容,Swift编译器可以有效地解决可怕的“空指针错误”。Objective-C不保证不返回nil。相反,Swift带有特殊类型的类型,称为“隐式解包的可选”,通常用于调用Objective-C代码。这些类型在Swift中被视为可选类型,以及存在检查所需的开销。您可以交替使用它,也可以使用与非可选类型相同的方法,但是如果Objective-C确实返回,则“ nil”将导致运行时错误。因此,Swift有一些编译时安全保证。
Ë。Swift和Objective-C之间的另一个微妙的不匹配之处在于消除了Apple两种编程语言在后台创建对象和类的方式。由于Objective-C具有动态特性,因此利用动态调度来调用对象上的方法(通过“ objc_msgSend”)。Swift肯定使用动态调度,但是由于它是静态类型的,因此还可以选择使用“ vtable”为每个调用方法存储函数指针。Swift使用的两种机制取决于许多因素。Plane Old Swift Objects将使用“ vtable”机制,除非该类中的类或方法使用“ @objc” Swift属性进行注释。
˚F。有机会从Objective-C类继承的Swift类将对继承的方法使用动态分配。但是,子类引入的任何新方法都是不可能的(嗯,您可以通过“ @objc”属性强制使用动态调度)。不用说Swift代码将能够与Swift类一起使用,但是Objective-C代码仅在带注释的情况下才能利用Swift对象和方法。
Swift在Apple实验室每天都在发展。您会遇到许多新知识,以了解Swift。这些包括泛型,与Objective-C库的交互,闭包,可选链和运算符重载。不可能在一篇文章中讨论所有这些内容以彻底描述一种新语言。如果你想了解更多内容,请联系我们济南网站建设。