前言

  主要是怕自己会忘记,所以摘录了网上一些关于swift3.1新特性的一些记录,总结下自己的看法。

数值类型的failable initialize

  Swift为所有的数字类型定义了failable initializer, 当构造失败的时候, 就会返回nil。直接看代码吧,比较直观:

let a = 2.21
let b = Int(a) //结果为2
let c = Int(exactly: a) // 结果为nil

let d = 2.0
let e = Int(exactly: d) //结果为2

就是说之前的直接转化是允许丢失精度的,Swift3.1的改动更加的严格了,如果丢失精度会直接返回nil;那么这个有啥作用呢?这么理解吧:如果你是知道需要转化的值的话,比如就是准确的2.11需要取正,那么确实没啥卵用;但是如果你想处理比如Any 可以代表任意类型的数据转化为数字类型的话,如果这个数字不是你期待的值就可以返回nil,你可以多一步的处理逻辑。

Sequence中新添加的两个筛选元素的方法

看下定义

protocol Sequence {
// ...
/// Returns a subsequence by skipping elements while `predicate` returns
/// `true` and returning the remainder.
func drop(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence
/// Returns a subsequence containing the initial elements until `predicate`
/// returns `false` and skipping the remainder.
func prefix(while predicate: (Self.Iterator.Element) throws -> Bool) rethrows -> Self.SubSequence
}

这两个方法的含义如下:

prefix(while:): 从数组的第一个元素开始,把符合while闭包条件的元素装进一个数组 A,直到不满足终止,返回数组A; 看下代码:

let arr = ["java","javascript","json","swift","shell","oc"]

let a = arr.prefix{$0.hasPrefix("j")}
let b = arr.prefix{$0.hasPrefix("s")}

print(a)
//输出 ["java","javascript","json"],满足含"j"前缀,直到遇到“swift”不满足二终止,返回数组
print(b)
//输出 [ ] 。第一个元素就不满足,直接终止返回数组
drop(while:):从第一个元素开始,跳过符合while闭包条件的元素,如果while条件不被满足,则终止判断,并将剩余的元素全部装进数组返回。看代码:

let arr = ["java","javascript","json","swift","shell","oc"]

let c = arr.drop {$0.hasPrefix("j")}
let d = arr.drop {$0.hasPrefix("a")}

print(c)
//输出 ["swift","shell","oc"],前面三个符合while条件,直接跳过,“swift”开始不满足终止,把剩下的元素装进数字并返回。

print(d)
// 输出["java","javascript","json","swift","shell","oc"],因为第一个就不满足直接终止了,剩下的元素就是整个数组。

通过available约束Swift版本

之前的写法:

#if swift(>=3.1)
func function1() {}
#elseif swift(>=3.0)
func function2() {}
#endif

现在可以这么写

为了表示某个API从特定版本之后才可用,可以这样:

@available(swift 3.1)
func function1() {}

为了表示某个API可用的版本区间,可以这样:

@available(swift, introduced: 3.0, obsoleted: 3.1)
func function2() {}

swift3.1针对@available进行了扩展,现在它不仅可以用于限定操作系统,也可以用来区分Swift版本号了。

使用具体类型在extension中约束泛型参数

在Swift3.1之前的版本中,如果想要在Int?类型添加一个方法的话,可能需要这样做:

protocol IntValue {
var value: Int { get }
}

extension Int: IntValue {
var value: Int { return self }
}

extension Optional where Wrapped: IntValue {
func something() -> Bool {
//do something here
}
}

在Swift 3.1里,实现起来更加的容易,代码也比较少,也比较容易阅读:

extension Optional where Wrapped == Int {
func something() -> Bool {
//do something here
}
}

写起来真是爽。

临时转换成可逃逸的closure

在Swift3.0函数的closure类型参数默认从escaping变成了non-escaping。这很好理解,因为大多数用于函数式编程的closure参数的确都以non-escaping的方式工作。

举个栗子:

func subValue(in array: [Int], with: () -> Int) {
let subArray = array.lazy.map { $0 - with() }
print(subArray[0])
}

注意,上面代码是不能编译通过的。因为lazy.map()是escaping closure,而with()是默认的non-escaping closure。如果根据编译器的指引,我们可能会在with:的后面添加@escaping:

func subValue(in array: [Int], with:@escaping () -> Int) {
let subArray = array.lazy.map { $0 + with() }
print(subArray[0])
}

Swift3.1给出了一个临时转换的方法:withoutActuallyEscaping(),我们的方法可以改写成下面这样:

func subValue(in array: [Int], with: () -> Int) {
withoutActuallyEscaping(with) { (escapingWith) in
let subArray = array.lazy.map { $0 + escapingWith() }
print(subArray[0])
}
}

withoutActuallyEscaping有两个参数,第一个参数表示转换前的non-escaping closure,第二参数也是一个closure,用来执行需要escaping closure的代码,它也有一个参数,就是转换后的closure。因此,在我们的例子里,escapingWith就是转换后的with。

关于内嵌类型

之前的版本的嵌套:

class A {
class B {
var value: T
init(value: T) {
self.value = value;
}
}
}

那么有点歧义 class A 中的T 和class B中的 T是同一个类型吗?为了避开这种歧义,在Swift 3.1里,我们可以把代码改成这样:

class A {
class B {
var value: T
init(value: T) {
self.value = value
}
}
}

这样看上去更加的清楚。

希望大家使用的时候可以多多提意见,大家一起进步!

Post Author: menglingfeng

发表评论

电子邮件地址不会被公开。 必填项已用*标注

You may also like

iOS OC语言copy修饰符实现原理

前言 在经过频繁的业

Label尺寸自适应与AutoLayout问题小结

水平布局与垂直布局L

iOS7之后的导航栏与控制器原点坐标问题

简单记录关于iOS7

%d bloggers like this: