您的委托方法可能不会在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 ,并声明它面对UICollectionViewDataSourceUICollectionViewDelegateFlowLayout协议。 我们没有在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?)->布尔 

叹。