您的委托方法可能不会在Swift 3中调用
Swift 3最明显的变化之一就是其命名约定。 在发布Xcode 8时,Apple还重命名了许多方法。
为了使新的Swift API与现有的Objective-C API兼容,Swift编译器将Swift 3方法转换为相应的Objective-C选择器,但有时这种转换不会发生。
最坏的情况是,您实现了委派方法,但从未调用它,并且您也不知道为什么。
在Swift 3中命名
Swift 3试图减少冗余。 在Swift 3之前的Objective-C或Swift中,我们曾经在方法的主体中包含参数名称,但现在其中许多参数已被删除。
苹果更新了其API指南,并在Cocoa和Cocoa Touch框架的Swift 3界面中重命名了许多方法,以遵循Swift 3的约定。苹果不仅更改了基本方法,还更改了协议中定义的委托方法。
例如,我们可以在Objective-C中使用一个委托方法,其选择器是“ collectionView:layout:sizeForItemAtIndexPath: ”,而在Swift 2中,它是
func collectionView(collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath)-> CGSize
“ IndexPath”出现三次。 Swift 3将其视为冗余,应将其删除。 因此,在Swift 3中,它变为:
func collectionView(_ collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAt indexPath:IndexPath)-> CGSize
如果您在类的主体中实现协议,则Swift 3的命名和Objective-C桥之间的转换将非常完美。 但是,如果您声明一个类面对某个协议,但是您在Swift扩展中实现了该协议,则Swift编译器不会进行此类转换。
Swift扩展中的委托方法
让我们来看看。 我们这里有一个UIViewController子类,它有一个UIColllectionView,它需要面对UICollectionViewDataSource和UICollectionViewDelegateFlowLayout协议。 现在看起来很完美。
如果将这些方法移到扩展中怎么办?
提出了几个错误。 它说:
方法’collectionView(_:layout:sizeForItemAt :)’提供的Objective-C方法’collectionView:layout:sizeForItemAt:’与需求的选择器不匹配(’collectionView:layout:sizeForItemAtIndexPath:’)
和
方法“ collectionView(_:cellForItemAt :)”提供的Objective-C方法“ collectionView:cellForItemAt:”与需求的选择器不匹配(“ collectionView:cellForItemAtIndexPath:”
为了使Swift编译器满意,您必须使用“ @objc ”注释来指定Objective-C选择器:
子类化和扩展
这是我们几个星期前见过的情况。 我们创建了一个超类KKViewController ,并声明它面对UICollectionViewDataSource和UICollectionViewDelegateFlowLayout协议。 我们没有在KKViewController中实现任何UICollectionViewDelegateFlowLayout方法,因为大多数UICollectionViewDelegateFlowLayout的方法都是可选的。
然后,我们将其子类化,子类为ViewController 。 我们在ViewController的扩展中实现了委托方法。 该方法的名称遵循Swift 3的约定,但从未被调用。
我们找到了解决此问题的两种方法。 一种是再次使用“ @objc ”注释,另一种是将其重命名为
func collectionView(_ collectionView:UICollectionView,布局collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:IndexPath)-> CGSize
等待! 它可以工作,但是不遵循API准则,对吗?
还有一件事
让我们看一下UICollection视图的另一种委托方法。 它是
func collectionView(_ collectionView:UICollectionView,canFocusItemAt indexPath:IndexPath)->布尔
如果在您的应用程序中实现该方法,则您的应用程序有时可能会崩溃。 为什么? 因为indexPath参数定义为非null,但是UIKit可以将nil传递给它。 如果您强制展开实际上值为nil的变量,则会引发异常。 在Swift.org上有一篇关于该主题的文章。
为防止您的应用崩溃,您应通过将方法命名为来使变量成为可选变量:
@objc(collectionView:canFocusItemAtIndexPath :) func collectionView(_ collectionView:UICollectionView,canFocusItemAt indexPath:IndexPath?)->布尔
叹。