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 definition

prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)

// Swift 2 calling code

viewController.prepareForSegue(segue, sender: something)

// Swift 3 definition

prepare(for segue: UIStoryboardSegue, sender: Any?)

// Swift 3 calling code

viewController.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 sentence

let word = wordList.word(1)

// Reads like a sentence

let 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

关键词

// sortED

func sortedAlphabetically() -> WordList {

...

}

// Remove is a verb

mutating func removeWordsContaining(_ substring: String) {

...

}

// RemovING

func 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 2

label.textAlignment = .Center

// Swift 3

label.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 2

doSomething {

self.finished = true

}

// Swift 3

doSomething {

finished = true

}

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

更多闭包细节见这篇 文章

-EOF-

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