1.委托模式的委托回调流程
2.委托模式为对象提供了一套接口,使其可由此将相关事件告知其他对象,将委托对象应该支持的接口定义成协议,在协议中把可能需要处理的事件定义成方法
比如UIScrollViewDelegate
@protocol UIScrollViewDelegate<NSObject>
@optional
// any offset changes
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
// any zoom scale changes
- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2);
// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// called on finger up if the user dragged. velocity is in points/millisecond. targetContentOffset may be changed to adjust where the scroll view comes to rest
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0);
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
// called on finger up as we are moving
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;
// called when scroll view grinds to a halt
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
// called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animatin
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
// return a view that will be scaled. if delegate returns nil, nothing happens
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;
// called before the scroll view begins zooming its content
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view NS_AVAILABLE_IOS(3_2);
// scale between minimum and maximum. called after any 'bounce' animations
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale;
// return a yes if you want to scroll to the top. if not defined, assumes YES
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;
// called when scrolling animation finished. may be called immediately if already at top
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;
@end
4.当某对象需要从另外一个对象中获取数据时,可以使用委托模式。这种情境下,该模式亦称为数据源协议。
比如UITableViewDataSource
@protocol UITableViewDataSource<NSObject>
@required
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
@optional
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; // fixed font style. use custom view (UILabel) if you want something different
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
// Editing
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
// Moving/reordering
// Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
// Index
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView __TVOS_PROHIBITED; // return list of section titles to display in section index view (e.g. "ABCD...Z#")
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index __TVOS_PROHIBITED; // tell table which section corresponds to section title/index (e.g. "B",1))
// Data manipulation - insert and delete support
// After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change
// Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
// Data manipulation - reorder / moving support
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
@end
5.委托对象应该用weak防止保留环
比如
@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
6.若有必要,可实现含有位段的结构体,将委托对象能否能响应相关协议方法这一协议缓存至其中,这样可以提升效率。
@protocol PersonDelegate <NSObject>
@optional
- (void)didEat;
- (void)didRun;
- (void)didSing;
@end
@interface Person : NSObject <NSCopying>
@property (nonatomic,copy) NSString *name;
@property (nonatomic,readonly) NSArray *friends;
@property (nonatomic,assign) int age;
@property (nonatomic,weak) id<PersonDelegate> delegate;
- (void)run;
- (void)eat;
- (void)sing;
@end
//.m
@interface Person (){
struct {
unsigned int didEat:1;
unsigned int didRun:1;
unsigned int didSing:1;
} _delegateFlags;
}
@property (nonatomic,readwrite,strong) NSMutableArray *friends;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(int)age
{
self = [super init];
if (self) {
self.name = name;
self.age = age;
_friends = [NSMutableArray array];
}
return self;
}
- (void)run{
//doSomeThing
if(_delegateFlags.didRun) [_delegate didRun];
}
- (void)eat{
//doSomeThing
if(_delegateFlags.didRun) [_delegate didRun];
}
- (void)sing{
//doSomeThing
if(_delegateFlags.didRun) [_delegate didRun];
}
- (void)setDelegate:(id<PersonDelegate>)delegate{
_delegate =delegate;
_delegateFlags.didEat = [_delegate respondsToSelector:@selector(didEat)];
_delegateFlags.didRun = [_delegate respondsToSelector:@selector(didRun)];
_delegateFlags.didSing = [_delegate respondsToSelector:@selector(sing)];
}
@end