作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
马可Mustapic
验证专家 在工程

Marco是一名资深iOS开发者,专注于游戏开发,尤其擅长编写概念原创应用.

以前在

智乐
分享

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开发.

斯威夫特改变了objective - c iOS开发者的游戏规则.

试用斯威夫特 vs. objective - c

为了开始探索斯威夫特,你需要做的是 从App Store下载XCode 创造一个实验场所. 本文中提到的所有示例都是以这种方式完成的.

苹果的斯威夫特主页 是学习斯威夫特编程的最佳参考. 你会发现它是无价的,直到你 完全跟上斯威夫特开发的速度 我相信你会经常回来的.

变量和常量

在斯威夫特中声明一个变量是用 var 关键字.

Var x = 1
var s = "Hello"

你会注意到两个变量 xs 是不同类型的. 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

斯威夫特再一次推断出的类型 f1f2 (字符串 -> 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

如前所述,斯威夫特中的Properties是用 var 关键字在类或结构定义内. 我们也可以用a来声明常量 声明.

结构体 FixedPointNumber
{
    var digits: Int
    让小数:Int
}

var n = FixedPointNumber(数字:12345,小数:2)
n.数字= 4567 //好的
n.小数= 3 //错误,小数是一个常数

还要记住,类Properties是强引用的,除非在它们前面加上 关键字. 但是,弱非可选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开发者吗, 谁还没有设法找到时间和学习斯威夫特语言的细节, 走上正轨,让飞禽带他们到一个新的高度.

聘请Toptal这方面的专家.
现在雇佣
马可Mustapic

马可Mustapic

验证专家 在工程

比利时根特

2013年3月1日成为会员

作者简介

Marco是一名资深iOS开发者,专注于游戏开发,尤其擅长编写概念原创应用.

作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

以前在

智乐

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 隐私政策.

世界级的文章,每周发一次.

输入您的电子邮件,即表示您同意我们的 隐私政策.

Toptal开发者

加入总冠军® 社区.