iOS 10 by Tutorials 笔记(一)

Chapter 1: What’s New in Swift 3 Swift 3 相对 Swift 2 带来了巨大的改变,首先很多以 NS 开头的框架都有了对应的,更加

Chapter 1: What’s New in Swift 3

Swift 3 相对 Swift 2 带来了巨大的改变,首先很多以 NS 开头的框架都有了对应的,更加 Swifty 的值类型,这样方便 Swift 在其他平台上进行推广。

对一些低级 C API 进行了封装,现在能像使用 Swift 原生类型一样去调用它们了。

最后是一些语言层级的变化,现在进入本章的内容

The Grand Renaming

首先是框架中方法名的变化,比较下面三个方法:

Objective-C

UITableViewCell *cell = [tableView cellForRowAtIndexPath: indexPath];

Swift 2

let cell = tableView.cellForRowAtIndexPath(indexPath)

Swift 3

let cell = tableView.cellForRowAt(indexPath)

我们关于方法命名可以总结三点:

  1. 方法命名尽量读起来像英语句子
  2. 变量名也作为句子的一部分
  3. 避免重复的词语

我们可以从 UIKit 和 Foundation 方法中看到这些变化

// Swift 2 definitionprepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) // Swift 2 calling codeviewController.prepareForSegue(segue, sender: something) // Swift 3 definitionprepare(for segue: UIStoryboardSegue, sender: Any?) // Swift 3 calling codeviewController.prepare(for: segue, sender: something)

Swift 3 方法被调用时,第一个参数前 label 会默认出现

// Function definition:func engageFluxCapacitor(fluxCapacitor: FluxCapacitor) // Called in Swift 2:timeMachine.engageFluxCapacitor(fluxCapacitor) // Called in Swift 3:timeMachine.engageFluxCapacitor(fluxCapacitor: fluxCapacitor)

Xcode 提供了迁移工具,方便我们自动处理

如果在第一个参数 label 前加 _表示调用时可以省略『参数 label』,因为第一个参数名已经使得方法名含义清晰了

func engage(_ fluxCapacitor: FluxCapacitor) // Called like this:timeMachine.engage(fluxCapacitor)

Overloading

如果两个方法,方法名都相同,只能依靠参数类型来区分,最好确定这两个方法做类似的事情,比如有两个 add(_:)方法,分别添加一个或添加多个元素,那么这种定义是 OK 的,毕竟他们在语义上做了相同的事情

但如果做不同的事情,比如有一个 VideoLoader 类,它有一个 VideoRequest 对象用来请求数据,另一个 VideoOutputHandler 用来处理数据。这样再用 add(_:)方法添加他们时就最好写成两个方法 addLoader(_:)addOutput(_:)

Grammatical rules

不要在参数前加 label,除非它读起来不是一个完整的句子

// Doesn't read like a sentencelet word = wordList.word(1) // Reads like a sentencelet word = wordList.word(at: 1) // Function definition:func word(at index: Int) -> String { ... }

有副作用的方法,应该用动词作为方法名

// "Sort" is a verb, the sorting is in-place,// so it is a side effect.mutating func sortAlphabetically() { ... }

在计算机科学中,函数副作用指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响。例如修改全局变量(函数外的变量)或修改参数。 函数副作用会给程序设计带来不必要的麻烦,给程序带来十分难以查找的错误,并降低程序的可读性。 严格的函数式语言要求函数必须无副作用。

值类型通常有一个不可变和可变的方法版本,一般会返回一个新实例然后修改,根据情况命名方法时加上 ed/ing关键词

// sortEDfunc sortedAlphabetically() -> WordList { ... }// Remove is a verbmutating func removeWordsContaining(_ substring: String) { ... }// RemovINGfunc removingWordsContaining(_ substring: String) -> WordList { ... }

命名 Bool 属性,最前面要加 is关键字

var isSortedAlphabetically: Bool

Foundation value types

Swift 3 中更多的 Foundation 类型有了值语义,比如之前就有的 String,现在又新增了 Date 等类型(对应了之前的 NSDate)

虽然是值类型,但由于底层采用了写时复制的机制(copy on write),并不会占用太多内存

Working with C APIs

GCD 和 Core Graphics 是 iOS 开发者使用最多的 C APIs,而 Swift 3.0 对其进行了封装。

新的 GCD 语法

let queue = DispatchQueue( label: "com.razeware.my-queue" qos: .userInitiated)queue.async { print("Hello from my serial queue!")}queue.async { print("Hello from my serial queue!")}queue.async { print("Hello from my serial queue!")}

Core Graphics 也一样

let transform = CGAffineTransform.identity .scaledBy(x: 0.5, y: 0.5) .translatedBy(x: 100, y: 100) .rotated(by: .pi / 4)let rectangle = CGRect(x: 5, y: 5, width: 200, height: 200) context.setFillColor(UIColor.yellow.cgColor) context.setStrokeColor(UIColor.orange.cgColor) context.setLineWidth(10) context.addEllipse(in: rectangle) context.drawPath(using: .fillStroke)

Language feature changes

最后是语言层面上的一些变化

Increment operators

自增自减运算符 counter++ 彻底被移除了

C-Style for loops

传统 C 风格的循环由于抛弃了 ++ 运算符,变成了

for i in 0..<10 { print(i)}

Currying syntax

柯理化语法被移除了

Key paths

我们在 OC 时代就大量使用 Key paths 和 key-value coding,不过它是工作在运行时,虽然很强大,但存在很多隐患。Swift 3.0 提供了更加安全的获取 key path 方式,并且他会在编译时验证。

class TimeMachine: NSObject { var currentYear = 2016}let timeMachine = TimeMachine() timeMachine.value(forKey: #keyPath(TimeMachine.currentYear)) // gives 2016

因为 key-value 只支持类,而且由 Objective-C runtime 来实现,所以如果要对原生 swift class 中的 属性使用 #keyPath语法,必须在声明这个属性时加上 dynamic 前缀。

class TimeMachine { dynamic var currentYear = 2016 var destinationYear = 1985}#keyPath(TimeMachine.currentYear) // "currentYear"#keyPath(TimeMachine.destinationYear) // Error

从 NSObject 继承的类定义属性时,无需加这个 dynamic

Access control

Swift 3 的访问控制关键词变成了 5 个:

  • open 代码完全公开,可以在任何地方进行子类化。一般用在 UIKit 和 Foundation 类中,鼓励继承
  • public 代码对外完全可见,但在同一个 module 中才允许继承
  • internal 代码对同一个 module 中的可见
  • fileprivate 代码在同一个文件内可见
  • private 代码只针对同一个声明内可见

关于 private 一般针对将一个文件用 extension 分割使用

class PotatoListViewController: UIViewController { private var potatoes: [Potato] ... }extension PotatoListViewController: PotatoSelectionDelegate { func didDelete(_ potato: Potato) { // potatoes 在此不可访问 potatoes.remove(potato) }}

Enums

枚举实例使用时都变成小写开头了

// Swift 2label.textAlignment = .Center // Swift 3label.textAlignment = .center

而在枚举中使用自身的时候也必需写 .xxx 而不能直接用 xxx 来表示了

enum Size { case Big case Little case Tiny var isSmall: Bool { switch self { // 不能这样写了,要写成 case .Big: return false case Big: return false case .Little: return true case .Tiny: return false} }}

Closures

Swift 3.0 中的闭包作为参数传入时,默认变成了非逃逸闭包(以前是逃逸闭包),如果需要逃逸闭包,就要手动声明为 @escaping

func doSomethingWith(_ this: Thing, then: @escaping (Thing) -> ()) { self.completion = then ... do stuff in the background ...}

而且在非逃逸闭包内部就不必使用 self 来明确作用域了

func doSomething(_ then: () -> ()) { // do something then() }// Swift 2doSomething { self.finished = true}// Swift 3doSomething { finished = true}

默认 non-escaping 有一个很重要的规则: 它只适用于作为参数传入函数的闭包。例如: 任何作为参数传入的闭包. 其它所有闭包都是 escaping 的

更多闭包细节见这篇 文章

-EOF-
未登录用户
全部评论0
到底啦