作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
2008年,苹果宣布并发布了iPhone SDK 2.0. 这一事件引发了软件开发的另一场革命,并诞生了一批新的开发人员. 他们现在被认为是 iOS开发者.
这些开发人员中的许多人以前从未使用过objective - c, 这是苹果向他们提出的第一个挑战. 尽管不熟悉语法和手动内存管理, 它非常成功, 在App Store中推出了成千上万款应用. 每次发布,苹果都会不断改进objective - c, 添加块和文字, 简化内存管理与自动引用计数, 以及许多其他现代编程语言的特征.
经过6年的改进和开发objective - c, 苹果决定向开发者抛出另一个挑战. 再一次,iOS开发者需要学习一门新的编程语言: 斯威夫特. 斯威夫特去掉了不安全的指针管理,引入了强大的新特性, 同时保持与objective - c和C的交互.
斯威夫特1.0已经是一个稳定而强大的开发平台, 在接下来的几年里,哪些肯定会以有趣的方式发展. 现在是开始探索这门新语言的最佳时机,因为它显然是iOS开发的未来.
本教程的目的是给出 objective - c语言的开发人员 快速概述斯威夫特语言的新特性, 帮助你迈出下一步,开始在日常工作中采用斯威夫特. 我不会花太多时间解释objective - c, 我假设你熟悉iOS开发.
为了开始探索斯威夫特,你需要做的是 从App Store下载XCode 创造一个实验场所. 本文中提到的所有示例都是以这种方式完成的.
苹果的斯威夫特主页 是学习斯威夫特编程的最佳参考. 你会发现它是无价的,直到你 完全跟上斯威夫特开发的速度 我相信你会经常回来的.
在斯威夫特中声明一个变量是用 var
关键字.
Var x = 1
var s = "Hello"
你会注意到两个变量 x
和 s
是不同类型的. x
是整数,而 s
是字符串. 斯威夫特是一种类型安全的语言,它会从赋值中推断出变量的类型. 如果你想让你的代码更容易读,你可以选择注释变量的类型:
变量y: Int
y = 2
常量与此类似,但声明它们时使用 让
而不是 var
. 在编译时不需要知道常量的值, 但是你必须只给它赋一次值.
让 c1 = 1 //编译时已知的常量
Var v = arc4r和om()
让 c2 = v //只在运行时知道的常量
顾名思义,它们是不可变的,因此下面的代码将导致编译时错误.
令c = 1
C = 3 //错误
其他类型也可以声明为常量. 例如, 下面的代码将数组声明为常量, 如果你试图修改任何元素, 斯威夫特编译器会报错:
Var arr2 = [4,5,6]
Arr2 [0] = 8
Print (arr2) // [8,5,6]
设arr = [1,2,3]
A[0] = 5 //错误
声明常量时需要初始化它们, 变量在使用前需要初始化. objective - c在哪里 零
等效? 斯威夫特介绍 可选值. 可选值可以有一个值,也可以是 零
. 如果你看一下下面的代码,你会注意到 x
被分配到 可选
的价值 2014
. 这意味着斯威夫特编译器意识到了 x
也可能是 零
.
Var s = "2014"
Var x = s.toInt ()
打印(x) //可选(2014)
如果在此代码中进行更改并赋值 “abc”
to s
,它不能转换为整数,您会注意到 x
现在是零
.
Var s = “abc”
Var x = s.toInt ()
Print (x) // 零
的返回类型 toInt ()
函数是 Int?
,这是一个 可选的Int. 我们试着调用一个标准函数 x
:
Var x = "2014".toInt ()
打印(x.继承者())//错误
编译器发出错误信号,因为 x
是一个 可选的,可能是零. 我们必须进行测试 x
首先,要确保 的继任者
函数在实数上调用,而不是在 零
值:
Var x = "2014".toInt ()
如果x != 零
{
打印(x!.继任者())// 2015
}
注意,我们必须展开 x
通过附加感叹号(!). 当我们确定 x
包含一个值,我们可以访问它. 否则我们会得到一个运行时错误. 我们也可以做斯威夫特调用的 可选的绑定,将可选变量转换为非可选变量
令x = "123".toInt ()
设y = x
{
打印(y)
}
的代码 if
语句将只在以下情况下执行 x
有一个值,并赋值给 y
. 注意,我们不需要展开 y
我们知道,它的类型不是可选的 x
不是 零
.
查看苹果的斯威夫特教程,了解更多关于可选选项和漂亮功能的详细信息 可选的链接
在objective - c中,格式化字符串通常使用 stringWithFormat:
方法:
NS字符串 *user = @"Gabriel";
Int days = 3;
NS字符串 *s = [NS字符串 stringWithFormat:@"post by %@ (%d days ago)", user, days];
斯威夫特有一个特性叫做 字符串插值 做同样的事情,但它更紧凑,更容易阅读:
让 user = "Gabriel"
让天= 3
Let s = "post by \(user) \(days) ago"
你也可以使用表达式:
设宽度= 2
设高度= 3
让 s = "边长\(宽)和\(高)的正方形的面积为\(宽*高)"
要了解更多斯威夫特的字符串插值和其他新特性,请访问 在这里.
斯威夫特中的函数定义与C不同. 函数定义示例如下:
func someFunction(s:字符串, i: Int) -> Bool
{
... / /代码
}
斯威夫特函数是一等类型. 这意味着您可以将函数赋值给变量, 将它们作为参数传递给其他函数, 或者让它们返回类型:
func stringLength(s:字符串) -> Int
{
返回countElements(年代)
}
func stringValue(s:字符串) -> Int
{
设x = s.toInt ()
{
返回x
}
返回0
}
func doSomething(f:字符串 -> Int, s:字符串) -> Int
{
返回f (s).继任者()
}
让f1 = stringLength
让f2 = stringValue
3 . doSomething(f1, "123") //
doSomething(f2, "123") // 124
斯威夫特再一次推断出的类型 f1
和 f2
(字符串
-> Int
),尽管我们可以明确地定义它们:
让 f1:字符串 -> Int = stringLength
函数也可以返回其他函数:
func compareGreaterThan(a: Int, b: Int) -> Bool
{
return a > b
}
func compareLessThan(a: Int, b: Int) -> Bool
{
return a < b
}
func comparator(greaterThan:Bool) -> (Int, Int) -> Bool
{
如果greaterThan
{
返回compareGreaterThan
}
其他的
{
返回compareLessThan
}
}
设f = comparator(true)
println (f(5、9))
可以找到斯威夫特函数指南 在这里.
斯威夫特中的枚举比objective - c中的要强大得多. 作为斯威夫特的结构体,它们可以有方法,并按值传递:
enum 移动Device: 字符串
{
iPhone = "iPhone", 安卓 = "安卓", WP8 = "Windows Phone8", BB = "BlackBerry"
func name() -> 字符串
{
回归自我.toRaw ()
}
}
设m = 移动Device.安卓
打印(m.name()) // "安卓"
与objective - c, 斯威夫特枚举可以赋值string, 字符或浮点数作为每个成员的值, 除了整数. 方便 toRaw ()
方法返回分配给每个成员的值.
枚举也可以参数化:
enum位置
{
case地址(街道:字符串,城市:字符串)
case LatLon(lat:Float, lon:Float)
func description() -> 字符串
{
开关的自我
{
情况下让 .地址(街道、城市):
返回街道+“,”+城市
情况下让 .LatLon(纬度、经度):
返回"(\(lat), \(lon))"
}
}
}
让loc1 = Location.地址(街道:“2070 Fell St”,城市:“San Francisco”)
让loc2 = Location.LatLon (lat: 23.117分,45分.899)
print (loc1.描述()) //“2070 Fell St, San Francisco”
print (loc2.Description ()) // "(23 ..117, 45.988)"
可获得有关枚举的更多信息 在这里.
元组将多个值分组为单个复合值. 元组中的值可以是任何类型,不必彼此具有相同的类型.
让 person = ("Gabriel", "Kirkpatrick")
print(人.0) //加布里埃尔
你也可以命名单个元组元素:
让 person =(第一个:"Gabriel",最后一个:"Kirkpatrick")
print(人.第一次)
元组作为需要返回多个值的函数的返回类型是非常方便的:
func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int)
{
返回(a/b, a%b)
}
print(intDivision(1,3)) // (3,2)
让 result = intDivision(15,4)
print(结果.余数)// 3
与objective - c不同,斯威夫特在switch语句中支持模式匹配:
设complex = (2.0, 1.//实部和虚部
开关复杂
{
Case (0,0):
println("Number is 0 ")
Case (_, 0):
println("Number is real")
默认值:
println("数字是虚数")
}
在第二种情况下,我们不关心数字的实部,所以我们用an _
来匹配任何东西. 您还可以检查每种情况下的附加条件. 为此,我们需要将模式值绑定到常量:
设complex = (2.0, 1.1)
开关复杂
{
Case (0,0):
println("Number is 0 ")
case (让 a, 0) w在这里 a > 0:
println("数是实数和正数")
case (让 a, 0) w在这里 a < 0:
println("数字是实数和负数")
情形(0,设b)其中b != 0:
println("数只有虚部")
情况设(a, b):
println("距离为虚数\(a*a + b*b)")
}
请注意,我们只需要绑定将要在比较语句或case语句中使用的值.
要了解有关元组的更多信息,请访问 在这里.
与objective - c, 斯威夫特不需要你为自定义类和结构体创建单独的接口和实现文件. 当你学习斯威夫特时, 您将学习如何在单个文件中定义类或结构, 并且该类或结构的外部接口自动提供给其他代码使用.
类定义非常简单:
类瓶
{
var 体积: Int = 1000
func description() -> 字符串
{
返回“这个瓶子有\(体积)ml”
}
}
设b =瓶()
打印(b.描述())
如你所见, 声明和实现在同一个文件中. 斯威夫特不再使用头文件和实现文件. 让我们给我们的例子添加一个标签:
类瓶
{
var 体积: Int = 1000
var标签:字符串
func description() -> 字符串
{
返回“这瓶\(标签)有\(体积)ml”
}
}
编译器会报错,因为label是一个非可选变量,并且在实例化Bottle时不会保存值. 我们需要添加一个初始化式:
类瓶
{
var 体积: Int = 1000
var标签:字符串
init(标签:字符串)
{
自我.标签=标签
}
func description() -> 字符串
{
返回“这瓶\(标签)有\(体积)ml”
}
}
或者,我们可以用 可选
类型为不初始化的Properties. 在下面的例子中,我们做了 体积
an 可选的整数
:
类瓶
{
var 体积: Int?
var标签:字符串
init(标签:字符串)
{
自我.标签=标签
}
func description() -> 字符串
{
如果自我.体积 != 零
{
这瓶\(标签)有\(体积)!) ml"
}
其他的
{
返回"A bottle of \(label)"
}
}
}
斯威夫特语言也是如此 结构体
,但它们比objective - c更灵活. 下面的代码教程定义了 结构体
:
结构体的座位
{
var row: Int
var信:字符串
init(行:Int,字母:字符串)
{
自我.行=行
自我.字母=字母
}
func description() -> 字符串
{
返回“\(行)- \(信)”
}
}
比如斯威夫特中的类, 结构可以有方法, Properties, 初始化器, 并遵守协议. 类和结构的主要区别在于 类通过引用传递,而结构体通过值传递.
这个例子演示了通过引用传递类:
设b =瓶()
打印(b.说明())//“b”瓶容量为1000毫升
Var b2 = b
b.音量= 750
print (b2.说明())//“b”和“b2”瓶750毫升
如果我们尝试类似的情况 结构体
,你会注意到变量是按值传递的:
var s1 =座位(排:14,字母:“A”)
Var s2 = s1
s1.字母= "B"
打印(s1.描述()) // 14-B
print (s2.描述()) // 14-A
什么时候使用 结构体
什么时候用 class
? 在objective - c和C中, 当需要对几个值进行分组时,可以使用结构体, 并期望它们被复制而不是被引用. 例如,复数、2D或3D点或RGB颜色.
一个类的实例传统上被称为对象. 然而, 斯威夫特的类和结构在功能上比其他语言更接近, 许多功能可以应用于类或结构类型的实例. 正因为如此,斯威夫特引用中更常用的术语是 实例
,它适用于这两个中的任何一个.
学习斯威夫特类和结构的基础知识 在这里.
如前所述,斯威夫特中的Properties是用 var
关键字在类或结构定义内. 我们也可以用a来声明常量 让
声明.
结构体 FixedPointNumber
{
var digits: Int
让小数:Int
}
var n = FixedPointNumber(数字:12345,小数:2)
n.数字= 4567 //好的
n.小数= 3 //错误,小数是一个常数
还要记住,类Properties是强引用的,除非在它们前面加上 弱
关键字. 但是,弱非可选Properties有一些微妙之处,因此请阅读 自动引用计数章 在苹果的斯威夫特指南中.
计算Properties实际上并不存储值. 而不是, 它们提供了一个得到ter和一个可选的setter来间接地检索和设置其他Properties和值.
下面的代码提供了一个计算值的示例 标志
:
enum标志
{
情况下积极
案例-
}
结构体 SomeNumber
{
var号码:Int
var标志:标志
{
得到
{
if number < 0
{
返回信号.负
}
其他的
{
返回信号.积极的
}
}
集(newSign)
{
if (newSign == newSign.消极的)
{
自我.Number = -abs(自我.号)
}
其他的
{
自我.Number = abs(自我 ..号)
}
}
}
}
我们也可以通过实现得到ter来定义只读Properties:
结构体 SomeNumber
{
var号码:Int
var isEven: Bool
{
得到
{
返回数字% 2 == 0
}
}
}
在objective - c中, Properties通常由实例变量支持, 由编译器显式声明或自动创建. 另一方面,在斯威夫特中, Properties没有相应的实例变量. 也就是说,不能直接访问Properties的后备存储. 假设我们在objective - c中有这个
// .h
@interface OnlyInitial字符串: NSObject
@property(strong) NS字符串 *string;
@end
// .m
@ implementation OnlyInitial字符串
- (void)set字符串:(NS字符串 *new字符串)
{
如果(部份.length > 0)
{
_string = [new字符串 substringToIndex:1];
}
其他的
{
_string = @"";
}
}
@end
因为在斯威夫特中,计算Properties没有后备存储,我们需要这样做:
类OnlyInitial字符串
{
var 最初的:字符串 = ""
var字符串:字符串
{
集(部份)
{
if countElements(new字符串) > 0
{
自我.最初的 = new字符串.substringToIndex(提前(部份.startIndex 1))
}
其他的
{
自我.Initial = ""
}
}
得到
{
回归自我.最初的
}
}
}
更详细地解释了Properties 在这里
斯威夫特中还有很多重要的新东西需要学习, 像泛型, 与objective - c库的交互, 闭包, 可选的链接, 操作符重载. 一本单独的教程无法全面描述一门新语言, 但我毫不怀疑会有更多关于学习斯威夫特编程的文章. 然而,我相信这一点 快速阅读 会帮助很多objective - c开发者吗, 谁还没有设法找到时间和学习斯威夫特语言的细节, 走上正轨,让飞禽带他们到一个新的高度.
比利时根特
2013年3月1日成为会员
Marco是一名资深iOS开发者,专注于游戏开发,尤其擅长编写概念原创应用.
以前在
世界级的文章,每周发一次.
世界级的文章,每周发一次.