ACCESSReactiveCocoa实践(三)—优化(译)

上一节中我们在先后的许多重大部分都是用了ReactiveCocoa编程技术,不过还有不少地方也足以接纳该技能,下边我们先导研商一下。

第一个地点是画廊界面。这多少个界面实现了六个代理:UICollectionView
dataSource, UICollectionView delegate以及大图浏览界面的delegate

俺们可以动用RACDelegateProxy对象实现再次回到值为void的代理方法。

委托代理(RACDelegateProxy)是目的的青石板。你调用rac_signalForSelector:
方法就可以收获一个信号,当选用器被调用是,该信号会发送一个新值。

注:
你必须保障(retain)委托代理(RACDelegateProxy)对象,否则它被放走掉就会发生

EXC_BAD_ACCESS至极。在画廊控制器中添加如下的私有属性:

@property(nonatomic,strong) id collectionViewDelegate;

你还需要#import the file RACDelegateProxy.h,
因为它不是ReactiveCocoa的中坚部分。
移除UICollectionViewDelegate和FRPFullSizePhotoViewControllerDelegate代理方法,在viewDidLoad方法中添加如下代码:

RACDelegateProxy* viewControllerDelegate = [[RACDelegateProxyalloc] initWithProtocol:@protocol(FRPFullSizePhotoViewControllerDelegate)];
[[viewControllerDelegate rac_signalForSelector:@selector(userDidScroll:toPhotoAtIndex:) 
        fromProtocol:@protocol(FRPFullSizePhotoViewControllerDelegate)] 
        subscribeNext:^(RACTuple *value) {
        @strongify(self);
        [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:[value.second integerValue] inSection:0]
                atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
}];

self.collectionViewDelegate = [[RACDelegateProxyalloc] initWithProtocol:@protocol(UICollectionViewDelegate)];
[[self.collectionViewDelegate rac_signalForSelector:@selector(collectionView:didSelectItemAtIndexPath:)]
    subscribeNext:^(RACTuple *arguments) {
    @strongify(self);
    FRPFullSizePhotoViewController *viewController = [[FRPFullSizePhotoViewController alloc] initWithPhotoModels:self.photosArray 
        currentPhotoIndex:[(NSIndexPath *)arguments.seconditem]]; 
    viewController.delegate =(id<FRPFullSizePhotoViewControllerDelegate>)viewControllerDelegate; 
    [self.navigationController pushViewController:viewController animated:YES];
}];

我们还是可以利用self调用rac_signalForSelector:方法([self
rac_signalForSelector:….])并采用同一的语句块。不过,我们还索要在控制器实现公文中保留空方法的票根,否则编译器会报“incomplete
implementation”的警告。

以此类中还有一个地方可以优化。除了改变状态,loadPopularPhotos方法并不曾做任何业务。假设ReactiveCocoa可以帮大家管理这个处境以来,我么就绝不顾虑它了。幸运的是,我刚刚知道应该怎么办。

咱俩得以移除这多少个方法并用如下的代码实现平等的功用:

RACSignal* photoSignal = [FRPPhotoImporter importPhotos]; 
RACSignal* photosLoaded = [photoSignal catch:^RACSignal*(NSError* error){
    NSLog(@"Couldn't fetch photos from 500px: %@", error);
    return [RACSignal empty]; 
}];

RAC(self,photosArray)=photosLoaded; 
[photosLoaded subscribeCompleted:^{
    @strongify(self);
    [self.collectionView reloadData];
}];

先是行调用了importPhotos方法,不同的是我们将回来的信号保存到一个当量当中。然后,咱们捕获(catch)信号传来的errors值并打印错误(和原先的逻辑一样,只可是使用了不同的语法)。catch:方法和subscribeError有轻微的区别。它同意非error的值穿过它,唯有当error值到来时它才调用语句块并传递error的值。我们在那里运用catch:这样非error的值就可以穿过去。catch:语句块反悔了一个空信号。

这段代码造成了好几“局部功能域污染”,可以利用如下等价的点子使代码更加彰着:

RAC(self, photosArray)=[[[[FRPPhotoImporter importPhotos]
    doCompleted:^{ 
    @strongify(self);
    [self.collectionView reloadData];
}]  logError] catchTo:[RACSignal empty]];

行使RAC宏,我们创造了一个单通道的绑定。我们将photosLoaded信号的最新值和photoArray属性绑定。很好,状态也归ReactiveCocoa管理了。

让大家转向collection view cell子类的贯彻:

@interfaceFRPCell() 

@property(nonatomic,weak)UIImageView* imageView; 
@property(nonatomic,strong)RACDisposable* subscription;

@end

@implementationFRPCell

-(id)initWithFrame:(CGRect)frame {
    ... 
}

-(void)prepareForReuse{ 
    [super prepareForReuse];
    [self.subscription dispose], self.subscription = nil;
}

-(void)setPhotoModel:(FRPPhotoModel*) photoModel {
    self.subscription = [[[RACObserve(photoModel, thumbnailData) filter:^BOOL(id value){
        return value != nil;
    }] map:^id(id value) {
        return [UIImage imageWithData:value];
    }] setKeyPath:@keypath(self.imageView, image) onObject:self.imageView];
}
@end

有多少个标识认证那多少个类可以动用ReactiveCocoa技术机一部优化。第一,大家有气象(subscription属性)。第二,大家手动处理RACDisposable的生命周期。每一遍你手动调用RACDisposable对象的dispose方法时,就象征还有交互性(more
reactive)更好有的的贯彻。
透过向FRPCell添加一个新的性质,
我们得以优化掉prepareForReuse方法。那多少个特性是photoModel(后面的章节中这是一个write-only属性,现在将它改为readwrite类型),将性能的扬言放在头文件中:

@property(nonatomic,strong)FRPPhotoModel*photoModel;

下一步,清除掉setPhotoModel:方法。取而代之的,大家观看photo
model的thumbnailData属性。在cell的伊始化方法中添加如下代码:

RAC(self.imageView,image) = [[RACObserve(self, photoModel.thumbnailData) 
    ignore:nil]  map:^(NSData *data) {
    return [UIImage imageWithData:data];
}];

小心我们是怎么拔取self观望photoModel.thumbnailData 键路径(key
path)而不是应用self.photoModel观看thumbnailData键路径,很微小但很关键的分别。当photoModel属性改变或者photoModel的
thumbnailData属性改变了,键路径photoModel.thumbnailData 就会触发KVO通告

现行大家得以把subscription属性完全除去了。

相关文章