今天在objc中国看了一篇文章,是关于如何让控制器代码更少的。文章地址
文章上介绍说,如果你的控制器有很多数据源方法,那么你可以把数据源方法的代码移植到一个单独的类中去,然后用 Block 来设置Cell 也可以用Delegate 。
于是我就按照上面的方法抽离了代码。
代码如下:
#import <Foundation/Foundation.h>
typedef void (^TableViewDataSourceBlock)(UITableViewCell *cell,id item);
@interface JKArrayDataSource : NSObject <UITableViewDataSource>
@property (nonatomic,strong) NSArray *items;
@property (nonatomic,copy) TableViewDataSourceBlock block;
-(instancetype)initArrayDataSourceWith:(NSArray *)anArrays Block:(TableViewDataSourceBlock)block;
@end
#import "JKArrayDataSource.h"
@implementation JKArrayDataSource
-(instancetype)initArrayDataSourceWith:(NSArray *)anArrays Block:(TableViewDataSourceBlock)block
{
self = [super init];
if (self) {
self.items = anArrays;
self.block = [block copy];
}
return self;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
id item = self.items[indexPath.row];
self.block(cell,item);
return cell;
}
@end
控制器代码如下:
#import "JKViewController.h"
#import "JKArrayDataSource.h"
@interface JKViewController ()<UITableViewDelegate>
@end
@implementation JKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *items = @[@"one",@"two",@"three"];
JKArrayDataSource *dataSource = [[JKArrayDataSource alloc] initArrayDataSourceWith:items Block:^(UITableViewCell *cell, id item) {
cell.textLabel.text = item;
}];
_tableView.dataSource = dataSource;
_tableView.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"%ld",(long)indexPath.row);
}
@end
看上去很和谐,但是一运行很荣幸的出错了。。。
Xcode上也没显示明显错误,就显示一句 EXE_BAD_ACCESS , 于是我忽然想到,UITableView 的 delegate 是弱引用的,它不会为计数器 +1 ,一旦某个对象被销毁,该实例的引用计数就会 -1 ,也就变成 0 ,而 delegate 就会变成 nil ,这时候该实例就会被ARC机制销毁,这种设计是为了防止循环引用导致内存泄露。
那么这时UITableView要去问它的代理对象索取数据的时候就发现它的代理对象没了,那么就出错了。。
这是一个非常基础的小问题,记录下来是为了让以后重视这类问题。
只要把代码改成这样就没问题了
@interface JKViewController ()<UITableViewDelegate>
@property (nonatomic,strong) JKArrayDataSource *dataSource;
@end
@implementation JKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *items = @[@"one",@"two",@"three"];
_dataSource = [[JKArrayDataSource alloc] initArrayDataSourceWith:items Block:^(UITableViewCell *cell, id item) {
cell.textLabel.text = item;
}];
_tableView.dataSource = _dataSource;
_tableView.delegate = self;
}