Swift 已经出了5个年头了,到如今,它的语法已经很稳定,iOS developers 能够放心使用了。我从1.0版本就开始使用 Swift,尽管也穿插了一些 Objective-C 项目,但整体来讲还算用得熟手。目前团队已经全面普及了 Swift,基本不会去写 Objective-C 了。本文写给还在用 Objective-C 的同行,但愿大家认真考虑一下 Swift。程序员
一开始接触 Swift 的人可能会对 ?
和 !
的操做很疑惑,甚至是浑身不自在。使用一段时间以后,就真香了。这个特性的用处是让编译器在编译时就把nil
异常检测出来,让开发者提早处理,从而不会把有这种问题的代码发到线上去。swift
Swift 的编译检测很是强大,这也是一门纯编译语言的优点。我也兼职写过一些 ruby 的后台,对 ruby 的运行时空异常深恶痛绝。ruby
NoMethodError (undefined method `hello' for nil:NilClass)
复制代码
你永远都不想在线上出问题,这就是 Optional 特性的意义。bash
打个比方,我简单地想使用一个url,这个url string是传过来的。闭包
let someURLString = "https://Çhello world"
guard let url = URL(string: someURLString) else {
fatalError("url went wrong \(someURLString)")
}
//..do something with url
print(url)
复制代码
当个人url字符串含有非法字符的时候,我会获得一个nil
,并可能在后续下面的代码抛出错误,致使crash。app
若是幸运的话,直接在当前的代码块就抛错了,那还好修复。若是这个nil
通过了不少层,那就糟糕了。网站
做为一门全新的语言,Swift 站在巨人的肩膀上,把枚举这种语言特性设计得简直完美。 好比,你的枚举类型能够是字符串的。ui
enum Gender: String {
case male
case female
}
print(Gender.male.rawValue)
复制代码
这样的话,避免一堆未定义的字符串横行。url
它还能够在内部定义方法,或者返回一个值,还能够遍历。举一个例子:spa
class ViewController: UIViewController {
let tableView = UITableView()
init() {
CellType.allCases.forEach { (cellType) in
cellType.register(to: tableView)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension ViewController {
enum CellType: String, CaseIterable {
case business1
case business2
var cellId: String {
return self.rawValue
}
func register(to tableView: UITableView) {
switch self {
case .business1: tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
case .business2: tableView.register(UINib(nibName: "SomeCell", bundle: nil), forCellReuseIdentifier: cellId)
}
}
}
}
复制代码
当理解了业务是一种互斥关系的时候,用枚举把这些列举出来,并在内部处理以后,返回一个值,减小大量的if else
,这样组织的话,代码就舒服了。
Objective-C 的 block 在实用方面已经作得很好,Swift 的闭包在此基础上再进一步。能够直接在里面声明所捕获的变量(好比self),众周所知,闭包/block这种代码组织方式可让代码更加紧凑,同时有捕获局部变量的好处。可是当一个方法写了一大块,里面含有一个闭包/block,不知道捕获了什么致使引用循环,这是难以调试的错误,所以在闭包内声明所捕获的变量是大有裨益的。
一般来讲,这个用在 weak self 来弱引用 self 就能完成大部分的事情。
login(phone: "xxx", password: "pswd") { [weak self] (success) in
self?.tableView.reloadData()
}
复制代码
因为 Swift 有空的检测,因此只用 weak self 不会有问题,好比你在闭包执行这样的代码是不行的,直接报编译错误:
var titles = [String]()
titles.append(self?.title)
复制代码
可是 Objective-C 的block可能会有存在的问题
[titles addObject: weakSelf.title];
复制代码
还有一点,或许是最重要的,就是咱们终于摆脱了 Objective-C 奇怪的 block 语法了!!这里有一篇总结得很好(注意网站名) fuckingblocksyntax.com
最近看了一部纪录片,叫《单挑荒野》,长期混B站的人可能熟悉,里面的主人翁艾德一个主旨就是,不但要生存下去,并且要活得滋润。程序员也同样,不但要实现功能,还得优雅地实现,写出让本身感到满意,舒服的代码。
实现一样的逻辑,Swift 可能不会比 Objective-C 少多少代码,但必定好看,舒服。
好比,你不须要声明这个变量的类型,由于在初始化的时候就已经知道。
let tableView = UITableView()
复制代码
vs
UITableView *tableView = [[UITableView alloc] init];
复制代码
好比枚举,你会常常看到 Objective-C 这样的代码:
typedef NS_ENUM(NSInteger, UIModalTransitionStyle) {
UIModalTransitionStyleCoverVertical = 0,
UIModalTransitionStyleFlipHorizontal __TVOS_PROHIBITED,
UIModalTransitionStyleCrossDissolve,
UIModalTransitionStylePartialCurl NS_ENUM_AVAILABLE_IOS(3_2) __TVOS_PROHIBITED,
}
复制代码
而 Swift 就舒服多了
enum UIModalTransitionStyle : Int {
case coverVertical
case flipHorizontal
case crossDissolve
case partialCurl
}
复制代码
我不太喜欢用NSAttributedString,由于感受老是把代码写得乱糟糟,但在 Swift 则舒服得多。
let attributedString = NSAttributedString(
string: "Hello world",
attributes: [
.font: UIFont.systemFont(ofSize: 14),
.foregroundColor: UIColor.blue
]
)
复制代码
还能够稍微扩展一下 Int 类型,能够写出更简洁明了的语句
extension Int {
var font: UIFont {
return UIFont.systemFont(ofSize: CGFloat(self))
}
var lineHeight: NSMutableParagraphStyle {
let para = NSMutableParagraphStyle()
para.maximumLineHeight = CGFloat(self)
para.minimumLineHeight = CGFloat(self)
return para
}
}
let attributedString = NSAttributedString(
string: "Hello world",
attributes: [
.font: 14.font,
.paragraphStyle: 20.lineHeight,
.foregroundColor: UIColor.blue
]
)
复制代码
差很少就想到这些,权当盘砖引玉,短短篇幅也没办法覆盖全部的 Swift 优势。