苹果Swift语言官方文档(中文翻译版)

本文档由长沙戴维营教育组织翻译和校对,由于英语水平有限,请大家指正。

长沙戴维营教育还为本教程录制了配套的视频教程在乌班图学院上免费提供,欢迎大家一起学习。

下面的章节,如果为蓝色链接表示以及翻译完毕,可以查看,如果为黑色则表示正在紧张的翻译中。本文档中文版每天都会更新,大家可以随时查看。如由Bug欢迎改正。


苹果Swift语言官方文档(中文翻译版)

本文档由长沙戴维营教育组织翻译和校对,由于英语水平有限,请大家指正。

长沙戴维营教育还为本教程录制了配套的视频教程在乌班图学院上免费提供,欢迎大家一起学习。

下面的章节,如果为蓝色链接表示以及翻译完毕,可以查看,如果为黑色则表示正在紧张的翻译中。本文档中文版每天都会更新,大家可以随时查看。如由Bug欢迎改正。


Swift与Objective-C API交互

Swift和Objective-C可以进行互操作,也就是说可以在Objective-C项目中使用Swift代码,反过来也可以。当然,这种互操作之间最重要的是可以在Swift中调用Objective-C的接口,毕竟目前绝大部分接口都是通过Objective-C提供的。

初始化

在Swift中实例化一个Objective-C的类时,可以用Swift语法调用它的一个初始化器。Objective-C的初始化方法被分割成关键字。例如“initWith”变成“init”,而剩下的部分作为方法的参数名。

Objective-C的代码:

  1. UITableView *myTableView = [[UITableView alloc] initWithFrame: CGRectZero style: UITableViewStyleGrouped];

对应的Swift代码为:

  1. let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

在Swift中不需要调用alloc方法,它会自动处理对象的创建功能。注意:Swift不会显式的调用init方法。

定义变量或者常量的时候,可以省略它的类型,Swift会自动识别。

  1. let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0))

为了方便起见,Objective-C的工厂方法被映射为Swift中的初始化器。例如:

  1. UIColor *color = [UIColor colorWithRed: 0.5 green: 0.0 blue: 0.5 alpha: 1.0];

转换为Swift:

  1. let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

属性访问

在Objective-C和Swift中访问属性都是使用点操作符。

  1. myTextField.textColor = UIColor.darkGrayColor()
  2. myTextField.text = "Hello world"
  3. if myTextField.editing {
  4. myTextField.editing = false
  5. }

访问和设置属性的时候不需要使用圆括号,上面darkGrayColor之所以有括号,是因为调用的是UIColor的类方法,而不是属性。

Objective-C中不需要参数并且有一个返回值的方法,可以被当作隐含的获取方法(getter),从而使用点操作符。但是在Swift中点操作符只能访问Objective-C中使用@property定义的属性。

方法调用

在Swift中使用点操作符调用Objective-C中的方法。

Objective-C的方法在Swift中调用的时候,它的第一部分成为Swift的基本方法出现在括号之前。然后函数的第一个参数没有名字,剩下的部分作为Swift函数对应的参数名称。 Objective-C语法:

  1. [myTableView insertSubview: mySubview atIndex: 2];

Swift代码:

  1. myTableView.insertSubview(mySubview atIndex: 2)

调用无参的方法:

  1. myTableView.layoutIfNeeded()

兼容id类型

Swift包含一个叫AnyObject的协议,与Objective-C中的id类似,可以表示任意类型的对象。AnyObject协议允许你在利用无类型对象的灵活性的同时保持类型安全。 你可以给AnyObject类型的变量赋任意的值:

  1. var myObject: AnyObject = NSData()

可以直接方法AnyObject类型对象的任意属性和方法,而不需要进行强制类型转换。

  1. let dateDescription = myObject.description
  2. let timeSinceNow = myObject.timeIntervalSinceNow

由于AnyObject类型的变量的类型需要到运行时才能确定,因此可能会导致不安全的代码。特别是你可以访问一个不存在的属性或者方法,它只是在运行时报错。

  1. myObject.characterAtIndex(5)
  2. //crash, myObject doesn't respond to that method

在进行类型转换的时候,不一定转换成功,因此Swift返回的是一个Optional值。你可以检查是否转换成功。

  1. let userDefaults = NSUserDefaults.standardUserDefaults()
  2. let lastRefreshDate: AnyObject? = userDefault.objectForKey("LastRefreshDate")
  3. if let date = lastRefreshDate as? NSDate {
  4. println("\(date.timeIntervalSinceReferenceDate)")
  5. }

如果你能够确定对象的类型,并且不为nil,可以使用as操作符进行强制转换。

  1. let myDate = lastRefreshDate as NSDate
  2. let timeInterval = myDate.timeIntervalSinceReferenceDate

nil对象

Objective-C中使用nil来表示引用一个空对象(null)。Swift中所有的值都不会为nil。如果需要表示一个缺失的值,可以使用Optional。

由于Objective-C不能确保所有值都非空,因此Swift将Objective-C中引入的方法的参数和返回值都用Optional表示。在使用Objective-C对象之前,应该检查它们是否存在。

扩展

Swift的扩展与Objective-C的类别有点类似。扩展能够为已有类、结构体、枚举等增加行为。

下面是给UIBezierPath添加扩展:

  1. extension UIBezierPath {
  2. class func bezierPathWithTriangle(length: Float, origin: CGPoint) -> UIBezierPath {
  3. let squareRoot = Float(sqrt(3))
  4. let altitude = (squareRoot * length) / 2
  5. let myPath = UIBezierPath()
  6. myPath.moveToPoint(orgin)
  7. myPath.addLineToPoint(CGPoint(length, origin.x))
  8. myPath.addLineToPoint(CGPoint(length / 2, altitude))
  9. myPath.closePath()
  10. return myPath
  11. }
  12. }

可以使用扩展增加属性(包括类属性或静态属性)。不过这些属性只能是通过计算得来,而不能进行存储。下面给CGRect添加一个area属性:

  1. extension CGRect {
  2. var area: CGFloat {
  3. return width * height
  4. }
  5. }
  6. let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
  7. let area = rect.area
  8. //area: CGFloat = 500.0

使用扩展可以在不创建子类的情况下让现有的类响应某个协议。需要注意的是,扩展不能覆盖已有的方法和属性。

闭包

Objective-C中的Block 被自动导入为Swift的闭包。例如:

  1. void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {
  2. /* ... */
  3. }

在Swift 中对应为:

  1. let completionBlock: (NSData, NSError) -> void = {
  2. data, error in /* ... */
  3. }

Swift的闭包和Objective-C中的Block是兼容的,可以在Swift中给Objective-C的方法传递闭包来代替Block对象。

闭包和Block对象有一点不同,里面的变量是可变的,也就是说与__block修饰的变量行为相同。

对象比较

Swift中有两种对象比较的方式。第一种是相等(==(equality),用来比较两个对象的内容是否相同。第二种是恒等(===(identity),比较两个变量或者常量是否引用同一个对象。

NSObject只能比较是否引用了同一个对象(恒等),如果要比较内容是否相同,应该实现isEqual:方法。

Swift类型兼容性

定义一个继承自NSObject或者其他Objective-C的类,它自动与Objective-C兼容。如果你不需要将Swift对象导入Objective-C代码的话,没必要关注类型的兼容性。但是如果在Swift中定义的类不是Objective-C类的子类,在Objective-C中使用的时候,需要用@objc进行说明。

@objc使得Swift的API可以在Objective-C和它的运行时中使用。当使用@IBOutlet@IBAction或者@NSManaged等属性时,自动添加@objc属性。

@objc还可以用来指定Swift中的属性或方法在Objective-C中的名字,比如Swift支持Unicode名字,包括使用中文等Objective-C不兼容的字符。还有给Swift中定义的函数指定一个Selectorde名字。

  1. @objc(Squirrel)
  2. class 长沙戴维营教育 {
  3. @objc(hideNuts:inTree:)
  4. func 欢迎光临(Int, 姓名: String) {
  5. /* ... */
  6. }
  7. }

@objc(<#name#>)属性作用在Swift的类上时,这个类在Objective-C的使用不受命名空间的限制。同样,在Swift中解归档Objective-C归档的对象时,由于归档对象中存放有类名,因此需要在Swift中用@objc<#name>说明Objective-C的类名。

Objective-C选择器(Selector)

Objective-C的选择器是方法的一个引用。在Swift中对应的是Selector结构体。使用字符串字面量可以构建一个选择器对象,如let mySelector: Selector = "tappedButton:"。由于字符串字面常量可以自动转换为选择器对象,因此可以在任何需要传递选择器的地方使用字符串字面常量。

  1. import UIKit
  2. class MyViewController: UIViewController {
  3. let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
  4. init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!)
  5. {
  6. super.init(nibName: nibName, bundle: nibBundle)
  7. myButton.targetForAction("tappedButton:", withSender: self)
  8. }
  9. func tappedButton(sender: UIButton!) {
  10. println("tapped button")
  11. }
  12. }

提示 performSelector:以及相关的调用选择器的方法没有被引入到Swfit中来,因为它们不是完全安全的。

如果Swift类继承自Objective-C的类,则它里面的方法和属性都能够作为Objective-C的选择器使用。而如果不是Objective-C的子类,需要使用@objc属性修饰,这个在前面的Swift类型兼容性中有描述。