swift4.0新特性的记录

最新在写swift的时候感觉不怎么顺手,于是把新特性看了一遍,顺便做一下笔记,加深一下记忆。

1、语法改进

extesion 中可以访问private的属性

例:

struct Date: Equatable,Comparable {
    private let secondsSinceReferenceDate: Double
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
    
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
    
}

这个是将Date实现Equatable,Comparable的协议。为了更swift话一下,可以将代码改造成。


struct Date {
    private let secondsSinceReferenceDate: Double // 结构体中定一个私有属性
}

// 扩展结构体,实现Equatable,Equatable协议
extension Date: Equatable {
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
}

extension Date: Comparable {
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}

swift4能这样调用,但是swift3将会提示错误,要把Date中的private改成fileprivate,这样会把作用域变大,造成属性的滥用。而swift4,就是将private的作用域变大,扩展到extension中,这样就不必更改属性的作用域了。

类型+协议 生成的组合类型

protocol Shakeable {
    func shake()
}

extension UIButton: Shakeable {
    func shake() {
        print("a")
    }
}
extension UISlider: Shakeable {
    func shake() {
        print("b")
    }
}

func shakeEm(controls: [UIControl & Shakeable]) {
    for control in controls where control.isEnabled {
        control.shake()
    }
}

这样就可以直接使用类型中遵循协议的方法,而不必要再判断cotrol是否遵循这个协议,然后在as一下来调用协议中的方法。

associatedtype 可以追加where的约束

protocol Shakeable {
    associatedtype Element where Self.Element == Self.Iterator.Element
    func shake()
}

这样可以避免在使用Shakeable时多做一个类型判断

key paths 语法的改变

因为以前的写法,这个在swift4上总是写的不舒服。swift4创建一个keyPath要用\开头

\keyPath

swift3使用setValue来写

@objcMembers class Kid: NSObject {
    dynamic var nickname: String = ""
    dynamic var age: Double = 0.0
    dynamic var friends: [Kid] = []
}
var ben = Kid(nickname: "Benji", age: 5.5)
let kidsNameKeyPath = #keyPath(Kid.nickname)
let name = ben.valueForKeyPath(kidsNameKeyPath)
ben.setValue("Ben", forKeyPath: kidsNameKeyPath)

而变成swift4就用了

struct Kid {
    var nickname: String = ""
    var age: Double = 0.0
    var friends: [Kid] = []
}
var ben = Kid(nickname: "Benji", age: 8, friends: [])
let name = ben[keyPath: \Kid.nickname]
ben[keyPath: \Kid.nickname] = "BigBen"

不是很习惯。
swift4的keyPath新特点:
1、可以定义class、struct,而不必加上@objcMembers、dynamic的关键字
2、类型安全和类型推断
3、可以用在所有的值类型上

下标支持泛型

现在下标用泛型不需要用as来转换类型了
例:

struct GenericDictionary<Key: Hashable, Value> {
    private var data: [Key: Value]

    init(data: [Key: Value]) {
        self.data = data
    }

    subscript<T>(key: Key) -> T? {
        return data[key] as? T
    }
}

let dictionary = GenericDictionary(data: ["Name" : "xx"])
let name: String? = dictionary["name"]

字符串

Unicode字符串在计算count时的正确性改善

var family = "👩"
print(family.characters.count)  // 1

去掉characters

现在string的某些属性可以不用characters。但是自动填充下有些加的characters的类型和不加的类型有些不同。

可以取单侧边界

新加语法糖...可以对字符串取单侧边界

let v = "hhgggdads"
let startSlicIndex = v.index(v.startIndex, offsetBy: 3)
let subvalue = v[startSlicIndex...]

String实现了Collection协议

因为实现了collection协议,所以现在可以调用collection 的方法
例:

//翻转字符串
let abc: String = "abc"
print(String(abc.reversed()))

//遍历
for i in abc {
    print(i)
}

//map
_ = abc.map {
    print($0.description)
}

//filter
let filterd = abc.filter { $0 == "b"}

//reduce
let result = abc.reduce("1") { (result, c) -> String in
    print(result)
    print(c)
    return result + String(c)
}
print(result)

Substring

在 Swift 中,String 的背后有个 Owner Object 来跟踪和管理这个 String,String 对象在内存中的存储由内存其实地址、字符数、指向 Owner Object 指针组成。Owner Object 指针指向 Owner Object 对象,Owner Object 对象持有 String Buffer。当对 String 做取子字符串操作时,子字符串的 Owner Object 指针会和原字符串指向同一个对象,因此子字符串的 Owner Object 会持有原 String 的 Buffer。当原字符串销毁时,由于原字符串的 Buffer 被子字符串的 Owner Object 持有了,原字符串 Buffer 并不会释放,造成极大的内存浪费。

在 Swift 4 中,做取子串操作的结果是一个 Substring 类型,它无法直接赋值给需要 String 类型的地方。必须用 String() 包一层,系统会通过复制创建出一个新的字符串对象,这样原字符串在销毁时,原字符串的 Buffer 就可以完全释放了。

多行字符串字面量

swift4可以把字符串写在一对"""中,这样字符串就可以写成多行。

let joke = """
Q: Why does  have  in their name?
A: I don't know, why does  have s in their name?
Q: Because otherwise they'd be called (punchline).
"""

标准库

Encoding and Decoding

swift4中引入Codable来解决对象持久话问题

struct Language: Codable {
    var name: String
    var version: Int
}

将language对象的实例持久化,只要language遵循Codable协议就好,然后encode成json或者PropertyList

//encode
let swift = Language(name:"swift",version: 4)
if let encode = try? JSONEncoder().encode(swift){
    // 保存encode

}

//decode
if let decoded = try? JSONDecoder().decode(Language.self, from: encoded) {
    print(decoded.name)
}

sequence的改进

protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    func makeIterator() -> Iterator
}

swift4的associatedtype支持追加where语句,这样获取Sequence的元素类型可以不用 Iterator.Element,而是直接取 Element。

Protocol-oriented integers

整数类型符合的协议有修改,新增了 FixedWidthInteger 等协议,具体的协议继承关系如下

            +-------------+   +-------------+
        +------>+   Numeric   |   | Comparable  |
        |       |   (+,-,*)   |   | (==,<,>,...)|
        |       +------------++   +---+---------+
        |                     ^       ^
+-------+------------+        |       |
|    SignedNumeric   |      +-+-------+-----------+
|     (unary -)      |      |    BinaryInteger    |
+------+-------------+      |(words,%,bitwise,...)|
       ^                    ++---+-----+----------+
       |         +-----------^   ^     ^---------------+
       |         |               |                     |
+------+---------++    +---------+---------------+  +--+----------------+
|  SignedInteger  |    |  FixedWidthInteger      |  |  UnsignedInteger  |
|                 |    |(endianness,overflow,...)|  |                   |
+---------------+-+    +-+--------------------+--+  +-+-----------------+
                ^        ^                    ^       ^
                |        |                    |       |
                |        |                    |       |
               ++--------+-+                +-+-------+-+
               |Int family |-+              |UInt family|-+
               +-----------+ |              +-----------+ |
                 +-----------+                +-----------+

ps:个人也不是很理解,只是参看了文档上的解释。

Dictionary and Set enhancements

dictionary和set增强的功能:
1、通过Sequence来初始化
2、可以包含重复的Key
3、Filter的结果的类型和原类型一致
4、dictionary的mapValues方法
5、dictionary的默认值
6、dictionary可以分组
7、dictionary可以翻转

NSNumber bridging and Numeric types

let n = NSNumber(value: 999)
let v = n as? UInt8 // Swift 4: nil, Swift 3: 231

swift4中,把值为999的NSNumber转换为UInt8后会返回nil,而swift3会返回231这个意外的值

MutableCollection.swapAt(::)

MutableCollection 现在有了一个新方法 swapAt(::) 用来交换两个位置的值

var mutableArray = [1, 2, 3, 4]
mutableArray.swapAt(1, 2)
print(mutableArray)
// 打印结果:[1, 3, 2, 4]

工程上

预编译 Bridging Headers 文件

编译器会预编译 Bridging Headers 文件,这样就不要在编译的时候每次都编译oc的头文件生成的swift文件,从加快了编译速度。

Indexing 可以在编译的同时进行

用 Swift 开发项目时,近几个版本的 Xcode 进行 Indexing 的速度慢的令人发指。Xcode 9 和 Swift 4 在这方面做了优化,可以在编译的同时进行 Indexing,一般编译结束后 Indexing 也会同时完成

COW Existential Containers

Swift 中有个东西叫 Existential Containers,它用来保存未知类型的值,它的内部是一个 Inline value buffer,如果 Inline value buffer 中的值占用空间很大时,这个值会被分配在堆上,然而在堆上分配内存是一个性能比较慢的操作。

Swift 4 中为了优化性能引入了 COW Existential Containers,这里的 COW 就代表 “Copy-On-Write”,当存在多个相同的值时,他们会共用 buffer 上的空间,直到某个值被修改时,这个被修改的值才会被拷贝一份并分配内存空间。

移除未调用的协议实现

struct Date {
    private let secondsSinceReferenceDate: Double
}
extension Date: Equatable {
    static func ==(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
}
extension Date: Comparable {
    static func <(lhs: Date, rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}

上面的例子,Date 实现了 Equatable 和 Comparable 协议。编译时如果编译器发现没有任何地方调用了对 Date 进行大小比较的方法,编译器会移除 Comparable 协议的实现,来达到减小包大小的目的。

减少隐式 @objc 自动推断

在 Swift 4 中,隐式 @objc 自动推断只会发生在很少的当必须要使用 @objc 的情况,比如:

复写父类的 Objective-C 方法
符合一个 Objective-C 的协议
其它大多数地方必须手工显示的加上 @objc。

减少了隐式 @objc 自动推断后,Apple Music app 的包大小减少了 5.7%。

OK笔记就到这,下面是参考资料:

WWDC 2017 Session 402 《What’s New in Swift》
WWDC 2017 Session 212 《What’s New in Foundation》
WWDC 2017 Session 102 《Platforms State of the Union》
《Swift Language Programming (Swift 4.0)》
https://github.com/apple/swift-evolution
https://github.com/ole/whats-new-in-swift-4
https://www.raywenderlich.com/163857/whats-new-swift-4
https://www.hackingwithswift.com/swift4

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容