下面兩種方式都是弱引用代理對(duì)象,但是第一種在代理對(duì)象被釋放后不會(huì)導(dǎo)致崩潰,而第二種會(huì)導(dǎo)致崩潰。
@property (nonatomic, weak) iddelegate;
@property (nonatomic, assign) iddelegate;
weak 和 assign 是一種 “非擁有關(guān)系” 的指針,通過這兩種修飾符修飾的指針變量,都不會(huì)改變被引用對(duì)象的引用計(jì)數(shù)。但是在一個(gè)對(duì)象被釋放后,weak會(huì)自動(dòng)將指針指向nil,而assign則不會(huì)。在iOS中,向nil發(fā)送消息時(shí)不會(huì)導(dǎo)致崩潰的,所以assign就會(huì)導(dǎo)致野指針的錯(cuò)誤unrecognized selector sent to instance。
所以我們?nèi)绻揎棿韺傩裕€是用weak修飾吧,比較安全。
控制器瘦身-代理對(duì)象:
我們將 UITableView 的 delegate 和 DataSource 單獨(dú)拿出來,由一個(gè)代理對(duì)象類進(jìn)行控制,只將必須控制器處理的邏輯傳遞給控制器處理。
UITableView 的數(shù)據(jù)處理、展示邏輯和簡(jiǎn)單的邏輯交互都由代理對(duì)象去處理,和控制器相關(guān)的邏輯處理傳遞出來,交由控制器來處理,這樣控制器的工作少了很多,而且耦合度也大大降低了。這樣一來,我們只需要將需要處理的工作交由代理對(duì)象處理,并傳入一些參數(shù)即可。
代理對(duì)象.h:
typedef void (^selectCell) (NSIndexPath *indexPath);
/**
* 代理對(duì)象(UITableView的協(xié)議需要聲明在.h文件中,不然外界在使用的時(shí)候會(huì)報(bào)黃色警告,看起來不太舒服)
*/
@interface TableViewDelegateObj : NSObject [UITableViewDelegate, UITableViewDataSource](因識(shí)別問題,這里將尖括號(hào)改為方括號(hào))
/**
* 創(chuàng)建代理對(duì)象實(shí)例,并將數(shù)據(jù)列表傳進(jìn)去
* 代理對(duì)象將消息傳遞出去,是通過block的方式向外傳遞消息的
* @return 返回實(shí)例對(duì)象
*/
+ (instancetype)createTableViewDelegateWithDataList:(NSArray *)dataList
selectBlock:(selectCell)selectBlock;
@end
代理對(duì)象.m:
#import "TableViewDelegateObj.h"
@interface TableViewDelegateObj ()
@property (nonatomic, strong) NSArray *dataList;
@property (nonatomic, copy) selectCell selectBlock;
@end
@implementation TableViewDelegateObj
+ (instancetype)createTableViewDelegateWithDataList:(NSArray *)dataList
selectBlock:(selectCell)selectBlock {
return [[[self class] alloc] initTableViewDelegateWithDataList:dataList
selectBlock:selectBlock];
}
- (instancetype)initTableViewDelegateWithDataList:(NSArray *)dataList selectBlock:(selectCell)selectBlock {
self = [super init];
if (self) {
self.dataList = dataList;
self.selectBlock = selectBlock;
}
return self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text = self.dataList[indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataList.count;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// 將點(diǎn)擊事件通過block的方式傳遞出去
self.selectBlock(indexPath);
}
@end
使用方法示例:
self.tableDelegate = [TableViewDelegateObj createTableViewDelegateWithDataList:self.dataList
selectBlock:^(NSIndexPath *indexPath) {
NSLog(@"點(diǎn)擊了%ld行cell", (long)indexPath.row);
}];
self.tableView.delegate = self.tableDelegate;
self.tableView.dataSource = self.tableDelegate;
iOS中的回調(diào)方法有很多,而代理和block功能更加相似,都是直接進(jìn)行回調(diào),那我們應(yīng)該用哪個(gè)呢,或者說哪個(gè)更好呢?
其實(shí)這兩種消息傳遞的方式,沒有哪個(gè)更好、哪個(gè)不好直說....我們應(yīng)該區(qū)分的是在什么情況下應(yīng)該用什么,用什么更合適!下面我將會(huì)簡(jiǎn)單的介紹一下在不同情況下代理和block的選擇:
從性能上來說,block的性能消耗要略大于delegate,因?yàn)閎lock會(huì)涉及到棧區(qū)向堆區(qū)拷貝等操作,時(shí)間和空間上的消耗都大于代理。而代理只是定義了一個(gè)方法列表,在遵守協(xié)議對(duì)象的objc_protocol_list中添加一個(gè)節(jié)點(diǎn),在運(yùn)行時(shí)向遵守協(xié)議的對(duì)象發(fā)送消息即可。
參考: