BLOCK完成后仅返回

时间:2015-06-08 15:52:08

标签: objective-c objective-c-blocks

我是否知道使用什么解决方案以使以下代码按顺序工作。

- (CGFloat)getRowImageHeight
{
    CGFloat defaultHeight   = 300.f;
    __block CGFloat height  = defaultHeight;

    [self configureImageTVCell:self.itemImageTVCell
                         block:^(UIImage *image, BOOL succeeded) {
                             if( succeeded )
                                 height     = image.size.height;
                         }];

    return height;
}

我希望BLOCK在返回高度之前完成,这是因为我想从BLOCK完成后获得最新高度。

我使用 dispatch_semaphore_t 尝试了一些解决方案,但它会导致模拟器实际挂起的死锁。

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[self configureImageTVCell:self.itemImageTVCell
                         block:^(UIImage *image, BOOL succeeded) {
                             if( succeeded )
                                 height     = image.size.height;

                             dispatch_semaphore_signal(semaphore);
                         }];

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

已经没想到这一点,确实需要帮助。

3 个答案:

答案 0 :(得分:1)

基本上,你要做的事情是不可能的。一方面,您有一个方法,您需要立即从中返回一个值:

- (CGFloat)getRowImageHeight
{
    // ... do some stuff ...
    return height;
}

另一方面,在代码的中间("做一些事情"),你正在执行异步操作:

[self configureImageTVCell:self.itemImageTVCell
                     block:^(UIImage *image, BOOL succeeded) {
                         // THIS IS ASYNCHRONOUS
                         if( succeeded )
                             height     = image.size.height;
                     }];

这意味着,根据定义,块中的代码将在未来某个未知时间运行。同时,您的外部方法getRowImageHeight已经完成并且很久以前就返回了它的值。

这是异步代码执行的本质。

您需要重新构建整个方法,以便它与您的异步代码一起使用。

当然,您还没有透露真正尝试做什么,所以我无法告诉您 如何重新架构它。但是,让我们假装您尝试使用要从Internet下载的图像填充表格视图的单元格。好吧,这是一个已经确定的问题,答案到处都是,包括很多关于Stack Overflow的好解释。所以你会读到这些答案。

答案 1 :(得分:1)

好的方法是这样的:

- (void)getRowImageHeightWithCompletionBlock:(void(^)(CGFloat height))completion {
    CGFloat defaultHeight = 300.f;
    [self configureImageTVCell:self.itemImageTVCell block:^(UIImage *image, BOOL succeeded) {
        if(succeeded && completion) {
            completion(image.size.height);
        }
    }];
}

答案 2 :(得分:0)

我想要做的事情是在视图加载时,我会在图像出现在视图之前预加载图像。然后获取图像块以返回图像高度,我想返回高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

但似乎上面的答案告诉我这种方法是不可能的。所以我尝试使用委托并将高度返回到主视图,并在单元格级别成功获取图像后使用下面的代码更新单元格高度。

- (void)reloadItemImageTVCellHeight:(CGFloat)height
{
    if( !self.hasUpdatedImageCellHeight ){
        self.hasUpdatedImageCellHeight   = YES;
        self.itemImageCellHeight        = height;
        [self.mTableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:ROW_IMAGE inSection:0]]
                         withRowAnimation:UITableViewRowAnimationNone];
    }
}

在viewDidLoad中,我将 self.hasUpdatedImageCellHeight 设置为,将 self.itemImageCellHeight 设置为 300.f < / strong>即可。 self.hasUpdatedImageCellHeight 是控制代表是否已经返回任何值,如果那么我会将其更新为以防止代表码再次呼叫&amp;试。

这是我的方法,但最好还是有一种方法可以在表视图完全加载之前本地知道图像高度。