近一段时间有做 iOS 的开发,经常会使用到 delegate,在使用的时候经常是对标 Android 中 listener 的功能,大致流程就是给宿主类设置一个 delegate,然后当宿主会要回传一些信息的时候,就调用 delegate 的方法。
举个例子:
@class TextSliderView;
@protocol TextSliderViewDelegate <NSObject>
- (void)progressDidChange:(TextSliderView *)sender progress:(CGFloat)progress;
@end
IB_DESIGNABLE
@interface TextSliderView : UIView
@property(nonatomic, weak) IBInspectable id<TextSliderViewDelegate> delegate;
@end
这是一个自定义的进度条 View,它会根据触摸/滑动的位置计算出一个进度,然后给到它的 delegate,通过方法 progressDidChange:progress:,而在 Android 中我们要实现一个类似的工作会怎么做呢,凑巧我也在 Android 上实现了一个同样的自定义 View,它的声明是这样的:
public class TextSliderView extends View {
private TextSliderViewListener mListener;
public interface TextSliderViewListener {
void onProgressChanged(float progress);
}
}
然后就会注意到,双方虽然是实现了同一个功能,但是从对回调方法的命名,以及声明的方式都不太一样。
当然关于声明方式,这里有语法层面的限制,在 objc 中没有内部类这种语法的支持,但是它支持一个文件中声明多个类;而 java 中每一个类/接口都要单独存在于一个文件,否则就只能采用内部类这种方式将两个类/接口声明在同一个文件中。
然后就是关于命名的区别,在 iOS 中,实现这样一个回调功能用的是 Protocol(协议),一般回调对象的命名叫做 delegate(委派人),Android 中更常使用的是 listener(监听者),从命名上给人的感觉就是不同的,delegate 给人的感觉是一个更主动地形象,宿主对象发布一个功能,delegate 去完成它,比如在 CollectionView 的使用中,它的 delegate 是 UICollectionViewDelegate,这个 delegate 中有很多待实现的方法,比如下面这些:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;
- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
看这些函数的实现,它们除了能够接受一些从 CollectionView 回传出来的一些信息外(didHighlightItemAtIndexPath/didUnhighlightItemAtIndexPath),还在一定程度上支撑着 CollectionView 的功能,比如 shouldHighlightItemAtIndexPath,这就意味着 CollectionView 的 delegate 确实不只是作为一个外部监听者来存在的,可能 CollectionView 的 dataSource 更能体现这一点。这些功能在 Android 中往往不是通过回调方法来做的,而是直接将对应的参数传递给宿主对象。
而反观 Android 中的 listener,listener 中方法的返回值往往是 void 或者简单返回一个表示自己执行状态的标志,一般情况下宿主的功能执行是不会依赖 listener 的执行的。
就拿 RecyclerView 和 CollectionView 对比,CollectionView 的 delegate 和 dataSource 功能的总和,就是 RecylerView.Adapter,并且 RecyclerView 也根本没有 listener 这种功能,我们如果要实现 item 的点击功能,一般就是直接在 Adapter 中再给 Adapter 添加一个 listener 用于监听点击事件。
通过以上的对比,简单总结下,iOS 中的 delegate 相对于 Android 中的 listener 来说,它被设计出来的用处是更加丰富的,除了可以用于接收宿主对象回传的信息之外,也可以作为宿主功能的一部分,相当于是将宿主的部分功能解耦出来,这是 delegate 的基本使用。相对的,在 Andoroid 中我们其实也是可以使用同样的功能达到一样的目的的,比如在宿主类中声明一些接口,将这些接口的实现作为宿主类功能的一部分,但就命名而言一般是不会使用 listener 这样一个命名的。