了解委托与阻止。 (重构代码使用委托代替块)

时间:2014-09-11 08:51:09

标签: ios objective-c uitableview delegates objective-c-blocks

我在网上找到了一个如何分离UITableview的数据源以使代码更可重用的示例。但是在此代码中,它使用块而不是委托来更新单元格。到目前为止,在我的项目中,我一直在使用委托,所以为了保持一致性,我希望它保持这种方式,所以如果有人可以解释更好的块并帮助我重构下面的示例代码以包含delegates而不是块,我会很高兴。我使用的示例来自http://www.objc.io/issue-1/lighter-view-controllers.html;

//
//  ArrayDataSource.h
//  objc.io example project (issue #1)
//

#import <Foundation/Foundation.h>


typedef void (^TableViewCellConfigureBlock)(id cell, id item);


@interface ArrayDataSource : NSObject <UITableViewDataSource>

- (id)initWithItems:(NSArray *)anItems
 cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock;

- (id)itemAtIndexPath:(NSIndexPath *)indexPath;

@end

的.m

//
//  ArrayDataSource.h
//  objc.io example project (issue #1)
//

#import "ArrayDataSource.h"


@interface ArrayDataSource ()

@property (nonatomic, strong) NSArray *items;
@property (nonatomic, copy) NSString *cellIdentifier;
@property (nonatomic, copy) TableViewCellConfigureBlock configureCellBlock;

@end


@implementation ArrayDataSource

- (id)init
{
    return nil;
}

- (id)initWithItems:(NSArray *)anItems
 cellIdentifier:(NSString *)aCellIdentifier
 configureCellBlock:(TableViewCellConfigureBlock)aConfigureCellBlock
{
    self = [super init];
    if (self) {
        self.items = anItems;
        self.cellIdentifier = aCellIdentifier;
        self.configureCellBlock = [aConfigureCellBlock copy];
    }
    return self;
}

- (id)itemAtIndexPath:(NSIndexPath *)indexPath
{
    return self.items[(NSUInteger) indexPath.row];
}


#pragma mark UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier
                                                        forIndexPath:indexPath];
    id item = [self itemAtIndexPath:indexPath];
    self.configureCellBlock(cell, item);
    return cell;
}

@end

它在UIViewController中的用法是;

void (^configureCell)(PhotoCell*, Photo*) = ^(PhotoCell* cell, Photo* photo) {
cell.label.text = photo.name;
};
photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos
                                            cellIdentifier:PhotoCellIdentifier
                                        configureCellBlock:configureCell];
self.tableView.dataSource = photosArrayDataSource;

我尝试每天学习新东西,如果有人可以提供帮助,那就太好了。有一天,我希望作为开发人员改进:)

我理解数据源的分离,但是使用块代替委托对我来说是新的(奇怪的)。

1 个答案:

答案 0 :(得分:2)

实际上,在您的示例中,ArrayDataSource类是&#34;泛型&#34;用于所有UITableView数据源的类。

如果仔细查看ArrayDataSource(ArrayDataSource.m)的实现,您会看到它调用UITableViewDatasource(numberOfRowsInSection:cellForRowAtIndexPath: ...)的经典方法。但是当泛型类必须为特定的indexPath配置单元格的内容时,它不知道如何处理id item,因此它调用一个特定的块(self.configureCellBlock(cell, item);)从泛型类外部化此行为。

块的概念就像函数指针一样,你只是告诉通用的ArrayDatasource类,当它必须在行self.configureCellBlock(cell, item);上配置一个单元格的内容时要调用什么函数。在您的情况下,单元格将显示照片的名称(cell.label.text = photo.name;)。

因此,在这种情况下,您仍然在ArrayDatasource类中使用UITableView的数据源概念,您可以将所有需求放在{{1}中的默认UITableViewDatasource (比如实现ArrayDataSource.m等等),以防止所有tableView数据源的复制粘贴(如果你的应用有很多heightForRowAtIndexPath:)。 这里的块的目的不是取代数据源概念,而是更方便地告诉泛型类要做什么......

我希望我清楚,但解释这些概念并不总是那么容易! :)