swift tips
可以预见今年的WWDC我们会迎来Swift3.0
,刚刚发布的2.2版本,已经在逐渐提示有些应该会改动的地方了,根据自己写Demo的过程逐渐记录了一些:
- for 循环的改动
不在完全C一样的风格了,这一点也可以看到swift的现代之处了,摒弃沉重的历史包袱,所以大胆的拥抱吧,eg:1
2
3
4
5
6
7
8
9
10
11
12
13
14// 数据遍历 - 推荐使用enumerate()
for (index, item) in items.enumerate() {
...
}
// 更加灵活的指定间隔,使用stride
for index int 2.stride(to: items.count, by: 2) {
print(index) // 2, 4, 6 ...
}
// 降序 - reverse()
for index in (0...100).reverse() {
print(index) // 100, 99, 98, 97 ... 0
}
但是,像复杂一些的多个组合逻辑的for,比如for(int i=0; i < sum && i / 2 == 0; ++i)
这样,如何合适的更改,现在还没找到合适的方法,目前我用的是while + if
- OC中的
__FUNCTION__
变为#function
, 不过这一累=类的变动Xcode都会提示你fix it ++ and – 终于 deprecated 了: 话说这样的语意不明的语法早TM该废了,果然没有包袱就是好,swift3中要使用:
1
i += 1
老古董
Selector
变动
从”functionName” >>>#selector(XXX.func)
1
selectBtn.addTarget(self, action: #selector(ViewController.selectPhoto), forControlEvents: .TouchUpInside)
guard
语法其实这个语法早在2.0版本就有了,但一直没有仔细使用,粗浅的涉猎并没有说服自己,直到3.0还保留看来是时候接受了,即便不使用的话完全也没什么影响,swift提供这种微妙的语法表达,很契合其简单明确的语言风格同时也保证了足够的健壮性
是否真的是这样呢?如需要将
string
转化为UInt8
,UInt8
本身已经实现了一个可接受string
的初始化方法并且可以抛出错误,但并还需要足够的提示来处理上下文我们不能预知的问题,比如格式错误,或者超出了数值边界,所以实现一个新的Init(fromString string: String)
可以抛出一个能够提供更具体错误信息的ConversionError
Tip: guard并不意味着要替换所有的if..else 和 if let,切忌滥用
1 | // 创建一个字符串转化为UInt8的初始化方法,并可抛出三种Error |
上边是传统的写法,我们明明只是补充一下3种可抛出错误,但这段代码很不容易看出来,至少一眼是看不出来的,如果用上了guard
,效果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16extension Unit8 {
init (fromString string: String) throws {
guard let _ = string.rangeOfString("^\\d+$", options: [.RegularExpressionSearch])
else { throw ConversionError.InvalidFormat }
guard string.compare("\(UInt8.max)", options: [.NumericSearch]) != NSComparisonResult.OrderedAscending
else { throw ConversionError.OutOfBounds }
guard let value = UInt(string)
else { throw ConversionError.Unknown }
self.init(value)
}
}
同样是想表达判断throw指定异常,使用guard语句比传统的明确很多,甚至到了一眼看出的程度
这里也能看到,原则是判断在前,最后执行self.init(value)
自swift变量的设计Optional
这一特性之初,从语言层面上虽说是现代的严谨的,但其实在很多时候增加了我们的代码量,常常时不时的需要嵌套的if let
才能保证后面对变量的强制解包的有效性,特别是在遇到复杂的Optional chain
情况下。
在刚刚学习的很长一段时间内都是靠着编译器的提示来过日子,还常常出现各种crush,这一点也算得上是入门swift 的最大门槛了,但总学if let
也swift
本身简洁的特质不符,好在终于有guard
帮我们分担了
guard
对我来说的另一个好处是,它不用让我随时操心if
逻辑不全的问题了,很多时候我在写的代码时总是自以为是的认为逻辑清晰,只写if
而不是保证if .. else
成对出现,这在逻辑复杂时或者嵌入式开发中迟早会遇到大的问题,但平白的写很多个else { }
总是显得不那么美观,感谢有了guard
🙏
比如在一个典型的Alamofire
请求之中:
1 | guard response.result.isSuccess |
👆的写法有待商榷,实际上很多人都不建议这样去写,else里面应该很简单,其次格式也不一定要这样,但是目前来看个人还是很认同这种规范的
- SupplementaryView的使用注意
- register要指定kind,自定义
UICollectionReusableView
dataSource代理中装填数据:
使用switch
区分装填1
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView
最重要的layout中要设置
headerReferenceSize
,否则代理方法not be called最大的一个坑,再给supplyView添加subView时,使用
bounds
而不能是frame
,否则就会出现所谓drop的现象1
2
3
4
5override init(frame: CGRect) {
super.init(frame: frame)
label.frame = bounds // 而不是frame
addSubview(label)
}
- 接上舒,还有几个不常用的方法,是作为cell滑动以及加动画场合的使用
1
2
3
4
5
6
7public func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath)
public func collectionView(collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, atIndexPath indexPath: NSIndexPath)
public func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath)
public func collectionView(collectionView: UICollectionView, didEndDisplayingSupplementaryView view: UICollectionReusableView, forElementOfKind elementKind: String, atIndexPath indexPath: NSIndexPath)
想不起来就去文档中看看,这里记下来一次