1.简介
在之前的文章[New learn]讲解Objective-c的block知识中介绍了block的相关知识。本章中我们将以一个实际例子来简单介绍一下block如何代替代理。
2.原有通过代理实现方式回顾
在[How to] 使用Xib来创建view中我们介绍了如何通过xib来自定义table的footview,如何通过代理的方式来通知controller去加载更多数据。
相应的代码:https://github.com/xufeng79x/tableView_groupbuy_test
1.在上述项目中我们在XFLoadMoreView.h头文件中声明了一个协议
@protocol XFLoadMoreViewDelegate <NSObject> /** * 当按钮点击后通知代理实现对象 * * @param loadMoreView 触发者本身 */ @optional -(void) loadMoreViewDidClickedToLoadBtn:(XFLoadMoreView *) loadMoreView; @end
2.在自定义的XFLoadMoreView中声明了代理属性:
代理属性,指向显示了此代理的对象,防止循环引用需要使用weak属性参数 @property (nonatomic,weak) id<XFLoadMoreViewDelegate> delegate;
3.在controller中去实现了此协议,并在创建XFLoadMoreView实例的时候将其代理属性值设定为当前controller,以此来进行通知调用。
@interface XFGoodsShowsViewController () <UITableViewDataSource, XFLoadMoreViewDelegate> 。。。。。。。。。。。 // 加载按钮按下后通知到此对象调用此方法 -(void) loadMoreViewDidClickedToLoadBtn:(XFLoadMoreView *) loadMoreView { // 这里我们模拟增加一个团购的信息,插入到列表的最好一行 XFGoodModel *model = [[XFGoodModel alloc] init]; model.image = @"image.jpg"; model.name = @"new food"; model.price = 123; model.soldNum = 321; // 将次信息插入到表数据源中 [self.goodsList addObject:model]; // 需要将此数据塞入table的最后一行 NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.goodsList.count - 1 inSection:0]; [self.goodsTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop]; // 加载完毕后将table滚到新加入的行那里,也就是最后一条 [self.goodsTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; } 。。。。。。。
3.使用block特性来替代代理特性机制
我们可以不使用通过协议以代理的方式去做,我们可以通过block来处理:
具体方法为:
1.在XFLoadMoreView.h文件中声明block属性,用于接收来自目标的回调block
// 定义通知回调 @property(nonatomic,strong) void (^notifyLoadBlock)(XFLoadMoreView *);
2. 将XFLoadMoreView.m类初始化方法中增加block参数
// 利用block来进行通知回调的初始化方法 +(instancetype) loadMoreViewWithNotifyBlock:(void (^)(XFLoadMoreView *)) notifyLoadBlock { // 直接从xib中加载view XFLoadMoreView *loadView = [[[NSBundle mainBundle] loadNibNamed:@"XFLoadButton" owner:nil options:nil] lastObject]; // 美化按钮,将按钮的四个角圆润化 loadView.loadMoreBtnView.layer.cornerRadius = 5; loadView.loadMoreBtnView.layer.masksToBounds = YES; // 设定加载更多回调block loadView.notifyLoadBlock = notifyLoadBlock; return loadView; }
3.在controller处初始化XFLoadMoreView的时候将具体block实现传入:
// 加载tableView的footview XFLoadMoreView *loadMoreView = [XFLoadMoreView loadMoreViewWithNotifyBlock:^(XFLoadMoreView * view){ [self loadMoreViewDidClickedToLoadBtn:view]; }];
这里重复利用了原有协议方式中的方法。
4.当自定义XFLoadMoreView中发生加载事件的时候去通知controller加载数据:
/** * 点击加载更多按钮后触发 */ - (IBAction)loadMoreClick { // 将botton隐藏让后将加载样式呈现 self.loadMoreBtnView.hidden = YES; self.loadMoreIngView.hidden = NO; // 使用此方法能够达到延迟执行效果 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ self.loadMoreBtnView.hidden = NO; self.loadMoreIngView.hidden = YES; // 向代理发送信息,由于是代理定义中设置的是可选方法,所以发送信息之前需要检查是否实现了此方法 // if ([self.delegate respondsToSelector:@selector(loadMoreViewDidClickedToLoadBtn:)]) // { // [self.delegate loadMoreViewDidClickedToLoadBtn:self]; // } // 使用回调进行加载通知 if (nil != self.notifyLoadBlock) { self.notifyLoadBlock(self); } });
4.总结
在本文中我们将一个原本通过代理的方式实现的功能通过block方式实现。
那么何时应该采用代理何时应该采用block呢?
我们可以参考如下文章:http://stackoverflow.com/questions/26791548/objc-memory-usage-of-delegate-vs-block
本章代码:https://github.com/xufeng79x/BlockDemo