Objective-C id 作为 Swift Any

Swift 3 与 Objective-C 的 API 接口比以前的版本更好用了。比如说,Swift 2 把 Objective-C 中的 id 映射为 Swift 中的 AnyObject ,它一般能储存类类型的值。Swift 2 同样为一些桥接的值类型提供了隐式的 AnyObject  ,比如说 String 、 Array 、 Dictionary 、 Set 以及某些数值,作为一种 Swift 原生类型可以方便地应用在 Cocoa API 上的便捷方式,比如 NSString 、 NSArray 、或者其他来自 Foundation 的容器类型。这些转换与其他语言不一致,这就导致了让人很难理解究竟什么被用作了 AnyObject ,从而玩出 Bug。

在 Swift 3 中,Objective-C 中的 id 类型现在映射为 Swift 中的 Any ,它描述了一个任意类型的值,无论是类、枚举、结构体还是其他 Swift 类型。这个变化致使 Objective-C API 在 Swift 中更加灵活,因为 Swift 中定义的值类型可以传送到 Objective-C API 中并作为 Swift 类型展开,消除了手动“包装”类型的需求。这些好处同时扩展了集合:Objective-C 集合类型 NSArray 、 NSDictionary 以及 NSSet ,它先前只接受 AnyObject ,现在可以包含 Any 类型。对于哈希容器,比如 Dictionary 和 Set ,现在有新的类型 AnyHashable 能保存任何遵循 Swift 中 Hashable 协议的类型。总的来说,从 Swift 2 到 Swift 3 的类型映射改动如下表:

Objective-C Swift 2 Swift 3
id AnyObject Any
NSArray * [AnyObject] [Any]
NSDictionary * [NSObject: AnyObject] [AnyHashable: Any]
NSSet * Set<NSObject> Set<AnyHashable>

很多情况下,你的代码就不会受到这个改变的影响。Swift 2 中隐式转换为 AnyObject 的代码在 Swift 3 中还是会照常作为Any运作。总之,还是有一些地方比如你声明的变量和方法需要改变并在 Swift 3 中获得最好的体验。同时,从 Swift 3 开始,在对象和值类型不能再隐式转换,如果你的代码显式地使用 AnyObject 或者 Cocoa 类比如 NSString 、 NSArray 或者 NSDictionary ,你就得引入更多显式地使用 as NSString 或者 as String 转换。Xcode 中的自动迁移工具在你从 Swift 2 迁移到 Swift 3 时将做最小的改动来保证你的代码可编译,但结果可能不能总是完美。这篇文章将描述一些你需要做的改动,以及一些获得 id 作为 Any 优势时需要规避的陷阱。

重写方法和遵循协议

当子类化一个 Objective-C 类并且重写它的方法、或者说遵循一个 Objective-C 协议时,在父类方法在 Objective-C 中使用时方法的类型特征就需要更新。某些通用的例子是 NSObject 类的 isEqual: 方法以及 NSCopying 协议的 copyWithZone: 方法。在 Swift 2 中,你可能会写一个 NSObject  的子类以遵循 NSCopying 比如这样:

在 Swift 3,为了做从 copyWithZone(_:) 到 copy(with:) 命名改变,你同样需要改变这些方法的特征来使用 Any 而不是 AnyObject :

无类型集合

属性列表,JSON以及用户信息字典在 Cocoa 中是通用的,并且 Cocoa 原生地把这些表示为无类型集合。在 Swift 2 中,必须用 AnyObject 或者 NSObject 元素来建立 Array 、 Dictionary 或者 Set ,依托于隐式绑定转换来处理值类型:

或者,你可能使用 Cocoa 容器类型,比如 NSDictionary :

在 Swift 3 中,隐式转换不再存在了,所以上边的代码都不会正常运行了。迁移工具可能会建议使用 as 单独地转换每一个值来保证这个代码正常运行,但这里有更好的解决办法。Swift 现在引入 Cocoa API 作为 Any 和(或) AnyHashable 的可接受集合,所以我们可以改变集合的类型来使用 [AnyHashable: Any] 代替 [NSObject: AnyObject] 或者 NSDictionary ,而不需要改变其他任何代码:

AnyHashable  类型

Swift 的 Any 类型可以处理任何类型,但 Dictionary 和 Set 需要 Hashable 的键,所以 Any 太通用而不能使用。从 Swift 3 开始,Swift 标准库提供一个新的 AnyHashable 类型,与 Any 类似,它作为所有的 Hashable 类型的父类,所以 String 、 Int 以及其他可哈希的类型可以被隐式地作为 AnyHashable 值,并且在 AnyHashable 之下的类型可以使用 is 、 as! 、 as? 搭台转换符号来动态地检查。 AnyHashable 会在从 Objective-C 引入无类型 NSDictionary 或者 NSSet 对象时使用,但它同样在纯 Swift 代码中作为创建牛逼合集或字典时好用。

未桥接上下文的显式转换

在确定的限制条件下,Swift 不能自动地桥接 C 和 Objective-C 构造。比如说,一些 C 和 Cocoa API 使用 id *  指针作为“输出”或者“输入输出”形式参数,并且自从 Swift 无法静态定义指针是如何使用的,它不能在内存中自动地执行桥接转换。万一如此,指针仍旧会显示为 UnsafePointer<AnyObject> 。如果你需要操作这些未桥接的 API,你可以显式地桥接转换,在你的代码中显式地使用 as Type 或者 as AnyObject 。

 

额外的,Objective-C 协议在 Swift 中仍然是类限制的,所以你不能让 Swift 结构体或者枚举直接遵循 Objective-C 协议或者通过轻量级的泛型类型使用它们。你需要显式地转换 String as NSString , Array as NSArray 等等,来操作这些协议和 API。

AnyObject  成员查找

Any 没有与 AnyObject 一样的查找魔法方法。这可能会打破某些 Swift 2 中查找属性或者发送信息给无类型 Objective-C 对象。比如说,这个 Swift 2 代码:

将会报错 description 不是 Swift 3 中 Any 的成员。你可以用 x[0] as AnyObject 转换来动态取回之前的行为:

或者,强制转换值为你需要的具体对象类型:

Objective-C 中 Swift 值类型

Any 可以处理任何结构体、枚举、元组或者其他你在 Swift 语言中可以定义的类型。Swift 3 中的 Objective-C 桥接可以相反表示任何 Swift 值作为兼容 id 的对象到 Objective-C。这能让 Cocoa 容器、 userInfo 字典以及其他对象中储存自定义 Swift 值类型更加简单。比如说,在 Swift 2 中,你可能要么在类中改变数据类型,要么手动包装它们,好把它们放进 NSSotification :

在 Swift 3 中,我们可以不用包装,直接把对象放进通知:

在 Objective-C 中, CreditCard 值将显示为 id 兼容, NSObject 遵循的对象,实现了 isEqual: hash 以及 description ,要是在 Swift 中,它使用 Swift 的 Equatable 、 Hashable 和 CustomStringConvertible 实现。对 Swift 来说,值可以通过动态转换为其原本类型来取回:

注意,在 Swift 3.0 中,某些 Swift 和 Objective-C 通用结构类型将会桥接为不透明对象而不是习惯上的 Cocoa 对象。举例来说,无论是 Int 、 UInt 、 Double 和 Bool 桥接为 NSNumber ,其他有大小的数值类型比如说 Int8 、 UInt16 等等。Cocoa 结构体比如 CGRect 、 CGPoint 以及 CGSize 同样桥接为不透明对象,尽管大部分 Cocoa API 可以使用他们作为 NSValue 实例的包装。如果你看到比如 unrecognized selector sent to _SwiftValue 这样的错误,说明 Objective-C 代码正在尝试调用一个不透明 Swift 值类型中的方法,你可能需要手动包装这个值为 Objective-C 代码期望的类型实例。

一个特殊的需要注意的问题是可选项。Swift 中的 Any 可以处理所有内容,包括可选项,所以就有可能转一个可选项给 Objective-C API 而没有事先检查它,就算 API 声明为接收非空 id 。这通常就会搞出一个涉及  _SwiftValue 的运行时错误而不是一个编译时错误。包含在 Xcode 8.1 beta 中的 Swift 3.0.1 可以实现这些处理数字类型、Objective-C 结构体以及通过定位上述 NSNumber 、 NSValue 和可选绑定限制穿透可选项:

要避免向前的兼容问题,考虑到未来版本的 Swift 可能允许更多 Swift 类型桥接到符合语言习惯的 Objective-C 类型上,你不应该依赖 _SwiftValue 类不透明对象的实现细节。

Linux 的可移植性

Swift 程序依靠 Swift 核心库运行在 Linux 上,它是一个使用 Swift 写的原生 Foundation 版本,无需 Objective-C 运行时来桥接。 id 即 Any 允许核心库来直接使用原生 Any 和标准库值类型,同时保持了与苹果平台使用 Objective-C Foundation 实现的兼容。自从 Swift 不再在 Linux 上与 Objective-C 进行交互,也就不再支持桥接转换比如 string as NSString 或者 value as AnyObject 。想要在在 Cocoa 和 Swift 核心库之间移植 Swift 代码,就应当仅使用值类型。

了解更多

id 即 Any 是一个 Swift 语言受早期 Swift 版本用户反馈并从开源 Swift 演进进程中受到启发而提升的重要范例。如果你想要了解更多关于 id 即 Any 背后的动机和设计决定,原本的 Swift 演进提议在 GitHub 的 swift-evolution 仓库中可见:

最终的结果就是,Swift 是一门更加一致的语言,Cocoa API 由 Swift 的使用变得更加强大。

在 iPad 上用 Swift Playgrounds 给机器人编程

在 WWDC 2016 我们发布了 Swift Playgrounds ,一个全新的使用 Swift 教学核心编程思想的 iPad 应用。除了苹果应用程序提供的牛逼功能之外,我们很高兴能看到 Swift 开发者社区将来会创建和分享的东西。我们在 WWDC 中呈现了一个名为介绍 Swift Playgrounds 的深入讨论环节,它向你展示了如何为 iPad 创建你自己的 .playgroundbook 文件,它拥有多页面、实时视图以及华丽的过场动画。

在这个 WWDC 环节中我们还在舞台上展示了在 iPad 上用 Swift Playgrounds 驱动控制一个 Sphero SPRK+ 机器人。由于 Swift Playgrounds 中的代码可以访问 iOS SDK,包括 CoreBluetooth 框架,你可以写一个能完全控制设备的程序比如说控制这些机器人。我们已经更新了在 WWDC 上展示的 playground,你可以看到它的原理,甚至是进一步扩展它的功能来教会你机器人更多小把戏。这个 playground 在文末可下载,你可以通过 iCloud、AirDrop以及邮件等方法把它传送到运行 Swift Playgrounds 的 iPad 上。

当你在 playground 的第一页运行代码时你会看到一个触摸界面来在室内手动驱动 Sphero 机器人。注意,它跑的很快!点击 playground 顶部的 Next Page 字样来移动到后续页面。这里你能访问一个简单的 API 来使用代码控制机器人,让你能够简单地写一个简短的程序来在移动机器人走方形、八字形等其他你喜欢的设计。

要运行这个 playground,你需要带有 64 位 CPU 的 iPad 并安装 Swift Playgrounds app 以及 iOS 10。你还需要一个支持蓝牙 LE 的 Sphero 机器人,比如说 BB-8 ,或者新的SPRK+。一旦机器人在附近,这个 playground 就会发现并允许你使用 Swift Playgrounds 来控制它。

你可以从 App Store下载 Swift Playgrounds

在 Swift 中使用 JSON

如果你的应用与 Web 应用通信,从服务器返回的信息经常是 JSON 格式。你可以使用 Foundation 框架里的 JSONSerialization 类来转换 JSON 为 Swift 的数据类型,比如 Dictionary 、 Array 、 String 以及 Bool 。总之,由于你不能确定应用接收的 JSON 的结构体或者值,可以通过挑战来正确地反序列化模型对象。这篇文章描述了几种你在应用中使用 JSON 时可以使用的方法。

从 JSON 中取出值

JSONSerialization 类方法 jsonObject(with:options:) 返回类型为 Any 的值并且在不能取得数据时抛出错误。

尽管有效的 JSON 可以只包含一个值,但从 Web 应用返回的 JSON 一般编码了一个对象或者以数组作为顶级对象。你可以在 if 或者 guard 语句中使用可选绑定和 as? 类型转换运算符来以常量的形式取出已知类型的值。要获从 JSON 对象类型中获取一个字典值,可以把它转换为 [String: Any] 。要从 JSON 数组类型获取一个数组值,可以转换为 [Any] (或者更具体的元素类型,比如 [String] )。配合下标或者枚举的类型匹配类型转换可选绑定,你可以通过键取出字典值或者通过索引取出数组值。

Swift 的内置语言特性使得通过 Foundation 的 API 解码 JSON 并安全地取出值十分简单——完全不需要额外的库或者框架。

从 JSON 取出的值创建模型对象

考虑到大多数 Swift 应用遵循 Model-View-Controller 设计模式,转换 JSON 数据到你应用中特定的对象模型定义中就显得十分给力。

比如说,当写一个提供本地餐馆搜索结果的应用,你可能需要实现一个接受 JSON 对象来初始化 Restaurant 模型,并实现一个类型方法使用 HTTP 请求服务器的 /search 终点然后异步返回 Restaurant 对象的数组。

比如说下面的 Restaurant 模型:

一个 Restaurant 拥有 String 类型的名字,一个使用坐标对表示的 location 以及一个包换内嵌 Meal 枚举的 Set 类型 meals 。

这里有一个服务器回复的餐厅例子,这是其中一条:

写一个可选 JSON 初始化器

要把 JSON 表示转换为 Restaurant 对象,写一个接收任何从 JSON 表示取出并转换为属性的实际参数的初始化器。

如果你应用与一个或者多个服务器通信,它们也不返回单一、固定的模型对象表示,考虑实现多个初始化器来处理每一种可能的表达方式。

在上边的例子中,每一个值都通过可选绑定和 as? 类型转换运算符从传入的 JSON 字典中取出到常量中。对于 name 属性,取出的 name 值就直接赋值给了它。对于 coordinate 属性,取出的 latitude 和 longitude 在赋值之前被组合成一个元组。对于 meals 属性,取出的字符串值被遍历到 Meal 枚举值的 Set 类型常量中。

写带有错误处理的 JSON 初始化器

先前的例子实现了一个可选的初始化器,如果反序列化失败就返回 nil 。

另外,你还可以定义一个类型遵循 Error 协议并且实现一个如果反序列化失败就抛出错误的初始化器。

这样, Restaurant 类型声明了一个内嵌的 SerializationError 类型,它使用关联值定义了丢失或者非法属性的枚举情况。在抛出版本的 JSON 初始化器中,不是用返回 nil 来表示失败,而是抛出了一个带有特定失败信息的错误。这个版本还验证输入数据来确保坐标表示是合法的几何坐标对并且每个在 JSON 中提到的 meals 的名字都能在 Meal 中对的上号。

写一个获取结果的类型方法

一个 Web 应用终端通常在一个 JSON 响应中返回多个资源。比如说,一个 /search 终端可能返回零到多个符合查询参数并带有其他元信息但包换这些表达的餐厅:

你可以在 Restaurant 结构体中创建一个类型方法来翻译查询方法形式参数为相应请求对象并发送 HTTP 请求到 Web 服务。这个代码同样也负责处理响应、反序列化 JSON 数据、从 "results" 数组取出的每一个字典创建 Restaurant 对象以及在一个回调函数中异步返回这些对象。

当用户输入文本到搜索栏来弹出一个table view显示匹配的结果时,视图控制器会调用这个方法:

通过这种方法分离重心来为从view controller访问餐厅资源提供一个一致的接口,就算 Web 服务的实现细节改变也无所谓。

总而言之

相同数据在表示形式上的转换是为了在不同的系统之间通信,这是一个写代码中无聊但必须的工作。

由于这些表现形式的结构可能十分相似,尝试创建一个高级抽象来在这些不同的表现形式之间自动映射是可行的。举例来说,一个类型使用 Swift 的 reflection API,可能定义一个在 下划线命名法 JSON 键与驼峰式命名法属性名之间的映射来自动地从 JSON 初始化一个模型,比如说Mirror

总之,我们发现这些抽象非但不能通过 Swift 语言方便的特性提供优越的好处,反而让调试问题变得更加棘手。在上边的例子中,初始化器不仅取出并从 JSON 映射值,还初始化复杂的数据类型并执行特定域名输入验证。基于reflection的方案为了完成任务把名字搞的老长。当你为自己的应用估算可用策略时要记得这些。大量的重复可能显然地比选错一个抽象更节省开销。

Swift 3 和 Xcode 8

Swift 3 beta 作为 Xcode 8 beta 的一部分来发布并且包含了大量的强化,很多贡献都来自开源社区。Swift 3 的主要目的是实现最新的主要源变动来使 Swift 始终保持语言的协调一致,为将来的版本发布提供更稳定的语法。

Swift 3 里保留的 Swift 语法和 API 让语言更感自然,并且在调用 Cocoa 框架时提供了更加 Swift-y[1] 的体验。流行的框架 Core Graphics 和 Grand Central Dispatch 现在在 Swift 中有了一个全新、更加清晰的接口。这次发布同时提升了编译性能,还包含了很多小的使它更加有趣的小改动。

Xcode 8 beta 包含了一个 Swift 文档和 Playground 的迁移助手来帮助你把你的现有代码迁移到 Swift 3 。

Swift 2.3

另外对于 Swift 3 来说,Xcode 8 支持使用 Swift 2.3 进行开发,一个对 Swift 2.2 语言的小升级,用来操作 macOS Sierra、iOS 10、tvOS以及 watchOS 3 的新 SDK。这样做的目的是为了允许开发者立即迁移到最新的 SDK,甚至是那些已经快用 Swift 2.2 开发完成并且还没有准备迁移到 Swift 3 的项目。Xcode 8 可以迁移你的代码到新的 Swift 2.3,它主要是把更加清晰的可空性添加到了新的 SDK 里了。比如说:

没有使用新 SDK 可空性定义的 Swift 2.2 Core Image 代码:

Swift 2.3 让可失败初始化器更加清晰:

或者:

Swift 3 是 Xcode 8 支持的主要开发语言所以如果你选择继续使用 Swift 2.3 进行开发的话,这里有几点需要注意。首先,Swift 2.3 和 Swift 3 并非二进制兼容所以你 app 的整个代码基础需要选择一个 Swift 版本。两个版本都可以被编译器、SDK以及调试器完全支持,但 IDE 的其他特性可能不会兼容 Swift 2.3。举例来说,Xcode 的 Playground 就只支持 Swift 3,并且注意 Swift Playground 的 iPad app 也使用 Swift 3。Xcode 项目模板都使用 Swift 3,所有的文档都是使用 Swift 3 格式展示的。

当 Xcode 8 在今年年末发布 GM 版本的时候,你将可以把无论 Swift 3.0 还是 2.3 写的 app 提交到 App Store。Swift 3 的改动体现了未来 Swift 的发展走向,我们强烈建议你预算一下时间来迁移你的 Swift 代码到版本 3 。就算是你第一次迁移到 Swift 2.3,你也可以稍后运行 Xcode 8 迁移助手来迁移 Swift 2.3 到 Swift 3 。


译注:

[1] Swift-y :“swift” 在英文中作为形容词意思为“迅速的”,“swifty”则不存在,所以写成了 swift + y,实际意思是说“强调更加的迅速”。

可交互的 Playground

Xcode 7.3 beta 3 中 iOS 和 OS X 的 Playground 添加了交互性,它允许你在 Playground 中与你写的代码进行点击、拖拽、输入以及其他交互。这些界面的响应将和它们在应用中完全一致。可交互的 Playground 可以帮助你快速建模和建立你的应用,并且提供了一个与你代码交互的完美方式。

任何指定到 XCPlaygroundPage 中 liveView 属性的视图和视图控制器都会自动地实现交互性,并且自从它在 Playground 中运行开始,你就可以得到所有通常的 Playground 结果。你可以实验动作识别,看看 UITableView 在你滚动的时候是如何创建和删除行的,或者在 SceneKit 中与复杂的 3D 场景互动。

示例 Playground

下面是一个使用在 iOS Playground 中 使用 UIKit 动态创建的高可交互并且可定制的牛顿摆,超适合你的桌面。

NewtonsCradle_2x

Swift 是开源的

Swift 现在开源了。今天苹果启动了开源 Swift 社区,同样惊艳的新工具和资源包括:

  • Swift.org ——一个用来做开源 Swift 社区的网站;
  • 公共代码仓库 github.com/apple
  • 一个新的 Swift 包管理器项目以简单地分享和编译代码;
  •  Swift 自带内核带有基于标准库的高级功能库项目;
  • 平台包括所有的苹果平台以及 Linux。

现在任何人都可以下载代码以及开发中编译来查看团队做到了什么程度。更多对项目贡献感兴趣的高级开发者可以提交 bug,参与社区,并且贡献他们自己的修复和增强来让 Swift 变得更加牛逼。对于开发 App Store 产品的开发来说,你应该使用 Xcode 中包含的稳定版 Swift,这仍然是提交APP的需求。

Swift.org

Swift.org 是一个为开源 Swift 而新建的网站。这个网站包含了想要帮助 Swift 迭代的开发者社区所需要的资源,贡献修复,更重要的是,与其他人互动。Swift.org 包含:

  • Bug 报告和追踪系统
  • 邮件列表
  • 为 Swift 工程建立的博客
  • 社区指南
  • 入门概览
  • 贡献指南
  • Swift 的文档
  • 开发者和 API 设计指南

Swift.org 是每日 Swift 工程工作的地方,作为开发者一起工作的社区,它把 Swift 带到新平台、添加新特性以及持续迭代这个我们最爱的语言。

源码

苹果在 GitHub 有了新家,坐标 github.com/apple 在这里你可以找到所有 Swift 项目的源代码。公共仓库包括了 Swift 编译器,LLDB 调试器以及 REPL,标准和核心库,包管理器以及其他所支持的项目。

GitHub 已经是开发者之间极其流行的合作之处。它可以很容易地直接在网页上阅读源码,或者快速检出代码到你的机器上。并且当你有补丁想要贡献的时候,我们接受推送请求。

Swift 包管理器

今天我们同样上线了一个全新的项目:Swift 包管理器。这个早期项目将会在一开始就以开源的形式开发。仓库在非常早期的状态,然后我们一起来定义一个伟大的包管理器将会是什么样子并且我们可以让它直观易用,然后给他足够的能力来在跨平台扩展,让 Swift 迅速繁荣起来。

核心库

苹果长期提供丰富的框架集合来提供通常被各种软件所需要的高级功能。那些框架比如 Foundation、libdispatch以及XCTest来让它更容易写出复杂的程序,并且我们想要确定开发者在把 Swift 技能带到新的平台时能够得到与之相同的收益。无论是给 iPhone 或 Mac 写应用,还是给 Linux 编译一个新的云服务,Swift 核心库都会给你提供可依赖的代码。

平台

开源 Swift 在 Mac 上运行,它能够为 OS X,iOS,watchOS 以及 tvOS 编译应用。Swift.org 同样提供了 Linux 版本的 Swift,完全兼容 Linux 工具集包括包管理器支持, LLDB 调试器以及 REPL。我们十分期待看到社区把 Swift 带到更多的新地方。作为学生和专业人员学习 Swift 编程, 每一个新平台和使用案例都为他们在整个技术行业打开了新的机遇。

现在就开始

Swift 不难。Swift.org 包含了二进制的编译器和命令行工具下载,包括苹果和 Linux 平台,这样你就可以快速开始了。最新的 Xcode 版本支持一个备用的工具链选项专门为了让你能够在 Xcode 里就能轻易地尝试最新开源版本的 Swift。并且 Swift.org 有牛逼的入门指南来带你概览整个设置环境以使用开源 Swift 工作的过程。

Playground 里的字面量

Xcode 7.1 里的新功能是嵌入文件,图像和颜色字面量到你的 Playground 代码里。字面量是你的数据以原本格式表示的实际值,直接显示于 Xcode 编辑器中。比如说不需要在编辑器里写 “myImage.jpg”——只需要从 Finder 拖动进你的图像,它就会以实际的样子在你代码行内显示。比起显示 RGB 值来表示颜色,Playground 将会渲染一个颜色样本。Playground 里的字面量与你手写的标准 Swift 代码有着极其相似的行为,但却使用了更好的方式渲染。

另外看起来更酷的是,字面量同时能让编辑资源变得更快。你可以使用颜色选择器来从调色板快速选择一个不同的颜色。通过从 Finder 拖拽文件到你的 Playground 代码里来立即使用它。你甚至可以在光标当前位置插入字面量,通过选择 Editor > Insert File, Image, 或者 Color Literal 双击字面量允许你简单地选择另一个值。

如果需要的话,资源会拷贝到你的 Playground 资源目录里,所以你 Playground 需要的一切都包含在了文档之中。因为字面量是你代码的一部分,你同样可以拷贝,粘贴,移动和删除你的源码。

Swift 代码里的字面量

字面量被翻译为特定平台类型,默认为下面列表所示:

对象字面量 OS X iOS and tvOS
Color NSColor UIColor
File NSURL NSURL
Image NSImage UIImage

要得到完整的字面量行内表示体验,你需要在 Playground 中使用。总之,如果你拷贝和粘贴使用字面量的代码到你的 Swift 代码中,粘贴的代码将会按照你预期的方式运行,Xcode 会直接把字面量渲染为纯文本。

为了让你开始使用字面量,我们已经在博文里包含了一个非常简短的 Playground。下载最新的 Xcode 7.1 beta 来试试这个 Playground

额外的文档

配合 Xcode 7.1 beta 3 的文档包含了更新了的 Playground 帮助文档和其他强大的 Playground 特性的更新信息,包含新的字面量内容。这里是相关子页面的直达链接:添加图片字面量添加颜色字面量,还有添加文件字面量

下面是在 Xcode 7.1 中字面量显示的演示截图:

literals_2x

App Store 里的 Swift 2 App

Swift 2 已经准备好面世了。你现在可以提交带有 Swift 2 最新特性的 app 。它让你的代码更加可读和给力,包括 guard ,新的错误控制模块以及可用性控制。

确保使用 Xcode7 来编译你的应用并且使用 OS X El Capitan 的 GM 版本,以及最终版本的 iOS9watchOS2

Xcode 7 和 OS X El Capitan

OS X El Capitan 需要 Xcode 7 ,它包括了 Swift 2 ,天生支持系统完整性保护(SIP),app thinning,以及最新的SDK,当运行 Xcode7 时,你可能会被提示一些需要应用在 Swift 1.2 代码上的语法改变。为了帮你迁移到 Swift2,Xcode7 包括了一个非常有用的工具来帮你重写旧版本的 Swift 代码。只需要选择菜单里的 Edit > Convert > To Latest Swift Syntax 然后 Xcode 就会迁移你的代码到最新的 Swift API 和语法。

如果你的代码在开发的后期阶段,你需要在 Xcode6在多停留一段时间,你得继续使用 OS X Yosemite 作为你的开发系统。OS X El Capitan 和 Xcode 6 的组合不能向 App Store 提交应用,因为基础体系结构进行了重大改变。如果你需要在另一个分区或者外接硬盘安装 OS X Yosemite,你可以从 App Store下载 OS X Yosemite,然后安装这些步骤来安装。同时注意 Xcode7 在 OS X El Capitan 和 Yosemite 上都是被支持的。

Swift 开发者的 SDK

在 Xcode 6.3 中,我们曾为 Objective-C 添加了新的 空值标记 语言特性。这个特点给了 Objective-C 语言一个与 Swift 相同的表达空与非空种类的 API 接口。Xcode 7 通过给 Objective-C 引入轻量泛型模块让 Objective-C 与 Swift 沟通更加自然。泛型允许两个语言安全的沟通和分享保存了特定种类元素的合集。 这些特性对任何写 同时包含 Swift 和 Objective-C 代码的 APP 的人来说都很有用。但是这里还有一些 Objective-C 开发者每天都在使用的更大的合集代码:组成苹果 SDK 的那些框架。为了提高 Swift Objective-C 的操作体验,我们倾全公司的努力来在我们的 SDK 头提供这个信息。在 Xcode 7你将会发现几乎所有的常见框架现在都在它们的 API 和合集类型的元素上支持了可空属性。这使得我们的 Swift 接口从这样:

  变成这样:

最后一个问题是 Xcode 7 转换你代码到 Swift 2 的工具。这个工具存在于 Xcode 的 Edit 菜单, Convert > To Latest Swift Syntax 。这个工具能把使用 Swift 1.2 编写的项目转换到合适的 Swift 2 版本,还会修改一些必要的配置。这些更改体现在升级的头部信息上。举个栗子,重写一个方法的时候它的参数和返回类型现在更加清晰易读,迁移器会更新你的方法来匹配之。 对于 Objective-C 的改善在 WWDC 的 Swift 和 Objective-C 的交互性 14分30秒处开始。不过这个视频使用 Xcode 6.3 __nullable 语法与 Xcode 7 中更新了的 _Nullable 语法不同。更多关于可空标注的信息,参见博文 空属性和 Objective-C  。对于 Swift 2 和 Objective-C 的轻量泛型,移步 Xcode 7 发布注释 来了解更多。


本文由落格博主作为学习之用个人翻译,版权归苹果官方博客所有,侵删。 如果要转载,请著明本页面的链接!

Swift 2 中的 String 字符串

Swift 提供了一种高性能的、兼容 Unicode 的字符串实现,这也成为了它自身标准库的一部分。在 Swift 2 中, String  类型不再遵守 CollectionType 协议,那时 String  是 Character  类型的集合,就像是数组。现在 String  提供了一种公开字符集合视图的字符属性。 为什么要这么改变?字符串作为字符的集合, String  类型的行为和数组集合以及字典有着相当大的不同,尽管这看起来是很合乎常理的模型。事实上也一直是这样,但是由于 Swift 2 添加的一些协议上的扩展导致了其根本上的一些必要的改变。

不同于其部分的总和

当添加一个元素到合集当中时,我们期望这个合集能够容纳这个元素。就好像你给数组末尾添加一个值,数组就容纳了这个值。集合与字典也是这个样子。总之,当你给给字符串末尾添加一个组合符号的时候,字符串中的内容会自动改变。 假设我们设定一个字符串cafe ”,也就是四个字符 c  , a  , f  , e  :

如果你在字符串末尾添加一个声调字符 “ U+0301 ” 也就是符号 “ ´ ” 字符串仍然拥有四个字符,但是最后一个字符却变成了“é 

字符串的字符属性不再包含原来的小写字母 “ e ” ,也不包含我们添加的声调符号 “ ´ ”。字符串现在包含了一个带着声调符号“´”的小写字母 “ é ” :

如果我们把其他合集都像字符串这样对待,那么比如说把 UIColor.redColor()  和 UIColor.greenColor()  添加到一个集合里然后集合就有了 UIColor.yellowColor()  将不足为奇。

基于内容字符的判断

另一个字符串和合集不同的地方是他们如何定义相等。

  • 两个数组只有同时拥有相同的长度,并且相应索引元素相等时候才会相等。
  • 两个集合只有同时拥有相同的长度,并且每一个元素都被两者包含时候才会相等。
  • 两个字典只有他们拥有相同的键值集合才会相等。

总之, String  是基于规范化相等来定义相等的。字符如果具有相同的语言意义和外形,我们就说它们规范化相等,就算是他们后台是由不同的 Unicode 组成也是一样。 比如说韩国的文字系统由24个符号或声调组成,代表单独的辅音和元音。只有把它们写出来的时候才会组成可读的字符。 举个栗子来讲,符号“가”([ga])由字符 “ᄀ” ([g]) 和 “ᅡ” [a]组成。在 Swift 语言当中,字符串的相等不再考虑它们是由分解还是复合字符序列:

再说一句,这个行为与 Swift 中任何合集都有巨大的不同。一个有着 ? 和 ?的数组被视为与 ?相等将变得不足为奇。

取决于你的角度

字符串不是合集。但它确实还是提供 CollectionType  视图的:

如果我们把刚才那个栗子 “café”拿过来,由分解的复合字符序列组成 [ c, a, f, e ] 还有 [ ´ ],这里是各种类型字符串视图,显示了它们的组成:

  • 字符属性把用户可感知字符文本(比如说c, a, f, 和 é)分割为扩展字形集群 。由于字符串必须遍历整个字符串中的每个位置(每个位置被称作代码点)以确定字符边界,访问此属性执行线性 0(n)时间。在处理那些包含人类可读文本字符串时,比如说那些 localizedStandardCompare(_:)  方法 和 localizedLowercaseString  属性等 高级区分区域 Unicode 算法应当有线逐字符处理。
  • Unicode标量 属性公开的基础标量值处存在字符串中。如果原始字符串使用预先组合的字符“ é”而不是分开的“ e + ´”,这将会反映在 Unicode 标量视图当中。当你执行字符数据的低级操作时,请使用这个API。
  • utf8utf16分别为了支持UTF-8和UFT-16表示法并提供代码点。这些值对应实际写入文件时候的特定编码。UTF-8代码单位在很多POSIX字符串处理API中使用,而UTF-16则在Cocoa和Cocoa Touch框架中表示字符串长度和偏移量。

更多关于Swift 编程语言的字符串和字符内容,请阅读 The Swift Programming Language 以及 Swift Standard Library Reference.


本文章内容翻译自苹果官方博客 Strings in Swift 2 ,系本人学习为之,水平有限,如有不妥之处欢迎留言斧正。