幸运的是,Swift 3 中就不会再出现这个情况了。字符串的 key-path 写法被替换为了 #keyPath()
:
class Person: NSObject {
var name:
String =
""
init(name:
String) {
self.name = name
}
}
let me =
Person(name:
"Cosmin")
me.value(forKeyPath: #keyPath(
Person.name))
|
延伸阅读:如果你想要了解更多该变更背后的故事,请阅读 David Hart 的观点。
Foundation 去掉 NS
前缀
我们先来看看有 NS
前缀时的写法,下面是一个典型的 JSON 解析例子(如果对 NS
前缀的前世今生感兴趣,请移步):
let file =
NSBundle.mainBundle().pathForResource(
"tutorials", ofType:
"json")
let url =
NSURL(fileURLWithPath: file!)
let data =
NSData(contentsOfURL: url)
let json =
try!
NSJSONSerialization.
JSONObjectWithData(data!, options: [])
print(json)
|
以上代码使用了 Foundation 相关类来对文件中的 JSON 数据进行解析:NSBundle -> NSURL -> NSData -> NSJSONSerialization。
在 Swift 3 中,将移除 NS
前缀,所以,解析流程变成了:Bundle -> URL -> Data -> JSONSerialization。
let file =
Bundle.main().pathForResource(
"tutorials", ofType:
"json")
let url =
URL(fileURLWithPath: file!)
let data =
try!
Data(contentsOf: url)
let json =
try!
JSONSerialization.jsonObject(with: data)
print(json)
|
延伸阅读:关于命名约定的变化,你可以查看 Tony Parker 与 Philippe Hausler 的观点。
M_PI
还是 .pi
下面是一个已知半径求圆周长的例子:
let r =
3.0
let circumference =
2 *
M_PI * r
let area =
M_PI * r * r
|
在旧版本的 Swift 中,我们使用 M_PI
常量来表示 π。而在 Swift 3 中,π 整合为了 Float,Double 与 CGFloat 三种形式:
Float.pi
Double.pi
CGFloat.pi
|
所以上面求圆周长的例子,在 Swift 3 中应该写为:
let r =
3.0
let circumference =
2 *
Double.pi * r
let area =
Double.pi * r * r
|
根据类型推断,我们可以将类型前缀移除。更为精简的版本如下:
let r =
3.0
let circumference =
2 * .pi * r
let area = .pi * r * r
|
GCD
Grand Central Dispatch(GCD)多用于解决网络请求时,阻塞主线程的 UI 刷新问题。这是用 C 写的,并且 API 对初学者也并不友好,甚至想要创建个基本的异步线程也不得不这样写:
let queue = dispatch_queue_create(
"Swift 2.2",
nil)
dispatch_async(queue) {
print(
"Swift 2.2 queue")
}
|
Swift 3 取消了这种冗余的写法,而采用了更为面向对象的方式:
let queue =
DispatchQueue(label:
"Swift 3")
queue.async {
print(
"Swift 3 queue")
}
|
延伸阅读:更多相关信息,请查看 Matt Wright 的观点。
更 Swift 范的 Core Graphics
Core Graphics 是一个相当强大的绘图框架,但是和 GCD 一样,它依然是 C 风格的 API:
let frame =
CGRect(x:
0, y:
0, width:
100, height:
50)
class View: UIView {
override
func drawRect(rect: CGRect) {
let context =
UIGraphicsGetCurrentContext()
let blue =
UIColor.blueColor().
CGColor
CGContextSetFillColorWithColor(context, blue)
let red =
UIColor.redColor().
CGColor
CGContextSetStrokeColorWithColor(context, red)
CGContextSetLineWidth(context,
10)
CGContextAddRect(context, frame)
CGContextDrawPath(context, .
FillStroke)
}
}
let aView =
View(frame: frame)
|
上面代码,首先创建了 view 的 frame,然后创建一个继承自 UIView
的 View
类,重写 drawRect()
方法来重绘 view 的内容。
在 Swift 3 中,有不同的实现方式——对当前画布上下文解包,之后的所有绘制操作就都基于解包对象了:
let frame =
CGRect(x:
0, y:
0, width:
100, height:
50)
class View: UIView {
override
func draw(_ rect: CGRect) {
guard
let context =
UIGraphicsGetCurrentContext()
else {
return
}
let blue =
UIColor.blue().cgColor
context.setFillColor(blue)
let red =
UIColor.red().cgColor
context.setStrokeColor(red)
context.setLineWidth(
10)
context.addRect(frame)
context.drawPath(using: .fillStroke)
}
}
let aView =
View(frame: frame)
|
注意:在 view 调 drawRect()
方法之前,上下文均为 nil
,所以使用 guard
关键字来处理(更多关于上下文的介绍,请移步)。