在视图控制器之间传递块

时间:2014-09-27 18:58:39

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

我搜索了很多,但无法找到我的具体问题的答案。但基本上我的问题是,我可以将完成块传递到另一个视图控制器并在新的视图控制器中重新定义它。

因此,例如在视图控制器A中,我有一个方法来使用完成块执行下载。首先,我在视图控制器A中创建我的块属性。

@property (copy)void (^downloadCompleteBlock)(NSArray *downloadItems);

我尝试将此更改为强而不是复制,但这并没有解决我的问题。

然后我按如下方式定义完成块。

self.downloadCompleteBlock = ^(NSArray *downloadItems) {

    NSLOG(@"download complete in view controller A";
};

然后我调用我的下载方法传递这个完成块。

[self download:self.downloadCompleteBlock];

但是,如果在离开此视图控制器时未调用此完成处理程序(如果下载未完成),我希望完成块在下一个视图控制器上执行不同的操作。所以在我准备segue时,我试图传入这个块来查看控制器B.

[controllerB setCompletionBlock:self.downloadCompleteBlock];

然后视图控制器B中的这个方法重新定义了调用此完成块时会发生什么。

- (void)setCompletionBlock:(void(^)(NSArray *downloadItems))downloadFinishedBlock {

downloadFinishedBlock = ^(NSArray *downloadItems) {

    self.collectionData = downloadItems;
    [self.collectionView reloadData];
};

}

然而,视图控制器中的原始块仍然在下载完成时被调用,而不是视图控制器B中的块。任何人都知道如果在下载之前加载该视图,如何在视图控制器B中调用完成块完成?我知道我可以使用通知程序,但我很好奇我是否可以使用块来执行此操作。

由于

1 个答案:

答案 0 :(得分:1)

这是一个棘手的问题。其核心是在第一个视图控制器消失后如何保持块的问题。您的当前代码通过让块引用self而无意中解决了该问题。 vc由该引用保留,如果它在请求完成时需要存在,这是个好消息,但这是个坏消息,因为现在vc和块将永远保留在一起。 (谷歌'保留周期'。)

那么我们如何获得一个长时间运行的进程,该进程在完成时运行一个块并且可能比两个或更多个视图控制器寿命更长?首先,将该过程分解为自己的对象。该对象的界面如下所示:

@interface DownloadThingy

@property (copy)void (^downloadCompleteBlock)(NSArray *);  // note, no need for dummy param names here
- (id)initWithRequestParams:(id)whateverIsNeededToStart;
- (void)start;

@end

现在,想要启动它的视图控制器可以向它声明一个强属性,创建一个,给它一个完成块(见下面**),并启动它。当它是segue的时候,它可以将downloadThingy传递给另一个vc,后者可以给它一个不同的完成块。

**由于请求对象在一个或多个vcs中保留为属性,并且由于它保留了块,因此您仍需要注意保留周期:     (VC-> downloadThingy->嵌段> VC)

在VcA中,执行以下操作:

- (void)startADownloadThingy {
    self.downloadThingy = [[DownloadThingy alloc] initWithRequestParams:someParams];
    __weak VcA *weakSelf = self;
    self.downloadThingy.downloadCompleteBlock = ^(NSArray *downloadItems) {
        // don't use self in here, use weakSelf
    }
}

VcB将在segue上被调用;它可能需要也可能不需要遵循相同的预防措施。区别在于第二个vc是否保留downloadThingy属性。如果它没有计划将其交给任何其他vc,它可以跳过该属性,从而省去对保留周期的担忧。

// another vc is handing off a running downloadThingy
- (void)heresARunningDownloadThingy:(DownloadThingy *)downloadThingy {
    // if we have our own property, then
    self.downloadThingy = downloadThingy;
    // and we need to do the weakSelf trick
    __weak VcA *weakSelf = self;
    self.downloadThingy.downloadCompleteBlock = ^(NSArray *downloadItems) {
        // don't use self in here, use weakSelf
    }
}

或者...

// another vc is handing off a running downloadThingy
- (void)heresARunningDownloadThingy:(DownloadThingy *)downloadThingy {
    // we do not have our own property
    downloadThingy.downloadCompleteBlock = ^(NSArray *downloadItems) {
        // feel free to use self in here
    }
}

最后一件事:DownloadThingy通过调用它来积极地nil阻止它后,这是一个很好的做法。所以当请求完成后,让它这样做......

// DownloadThingy.m
// request is complete
self.downloadCompleteBlock(arrayFullOfResults);
self.downloadCompleteBlock = nil;