Ios 什么';这是在嵌套块中保留对象的正确方法

Ios 什么';这是在嵌套块中保留对象的正确方法,ios,multithreading,thread-safety,objective-c-blocks,Ios,Multithreading,Thread Safety,Objective C Blocks,我想为表视图中的每一行下载图像,所以我编写了一个使用block的方法 我认为indexPath和tableView可能不会被completion块复制,因为它们在If语句中使用。所以我在完成区块执行之前保留它们 代码是: - (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(

我想为表视图中的每一行下载图像,所以我编写了一个使用block的方法

我认为indexPath和tableView可能不会被completion块复制,因为它们在If语句中使用。所以我在完成区块执行之前保留它们

代码是:

- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath
{
    NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;

    UITableView *strongTableView = [tableView retain];
    NSIndexPath *strongIndexPath = [indexPath retain];

    [self.downloadManager downloadImageAtURL:imageURL
                                  identifier:[self identifierForIndexPath:indexPath]
                                      serial:serial
                                  completion:^(UIImage *image) {
                                      if (image) {
                                          [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                              [cachedImagesOfURLs setObject:image forKey:imageURL];

                                              id cell = [strongTableView cellForRowAtIndexPath:strongIndexPath];
                                              if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
                                                  [cell didDownloadImage:image withName:name];
                                              }
                                          }];
                                      }

                                      [strongTableView release];
                                      [strongIndexPath release];
                                  }];
}
但结果是,当完成块执行并尝试创建一个块并在主线程中运行它时,它崩溃了。调试器打印“-[XXX cellforrowatinedexpath:]:发送到实例的无法识别的选择器”。我觉得tableView和indexPath都被释放了

但我不知道为什么,我一直试图留住他们。有人能告诉我如何防止这次撞车吗?多谢各位

我认为这就足够了

- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath
{
    NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;

    [self.downloadManager downloadImageAtURL:imageURL
                                  identifier:[self identifierForIndexPath:indexPath]
                                      serial:serial
                                  completion:^(UIImage *image) {
                                      if (image) {
                                              [cachedImagesOfURLs setObject:image forKey:imageURL];

                                              id cell = [tableView cellForRowAtIndexPath:indexPath];
                                              if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
                                                  [cell didDownloadImage:image withName:name];
                                              }
                                      }
                                  }];
}

甚至更少的代码。不确定您所引用的代码位是如何工作的,但从名称来看,我猜以下内容就足够了:

- (void)downloadImageAtURL:(NSString *)imageURL name:(NSString *)name serial:(BOOL)serial forTableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {

    NSMutableDictionary *cachedImagesOfURLs = self.cachedImagesOfURLs;

    [self.downloadManager downloadImageAtURL:imageURL identifier:[self identifierForIndexPath:indexPath] serial:serial completion:^(UIImage *image) {
        if (image) {
            [cachedImagesOfURLs setObject:image forKey:imageURL];
            id cell = [strongTableView cellForRowAtIndexPath:strongIndexPath];
            if ([cell respondsToSelector:@selector(didDownloadImage:withName:)]) {
                [cell didDownloadImage:image withName:name];
            }
        }
    }];
}

但是需要保留这个吗?您是否直接在块中尝试了方法变量?我认为它可能会工作块复制了它需要的变量。不需要显式保留。不要在块中引用self.downloadManager。你真的应该切换到ARC@直到是的…我真的这么认为。但我必须支持iOS 4.3,iOS 4.3 SDK不支持弱属性。当我的部署目标升级到iOS 5时,我将使用ARC…你可以在iOS4.3上使用未维护的不安全_,因此ARC在该操作系统上是完全可能的-只是不具备它的所有功能。可能不需要向mainQueue添加操作,完成块本身可能在主线程上运行。“完成块本身可能在主线程上运行”你怎么会这样想?@newacct,我不确定它是否会,但如果我写的是“下载管理器”,比如NSURLConnection,我会在主线程上调用块。我会告诉我的调用者,完成块可能用于更新UI,因此我会在主线程上调用它作为一种方便。@LithuT.V完成块不是在主线程上运行,而是在它开始下载的线程上运行。我认为这个问题不是由这个引起的。不过还是谢谢你。@danh你说得对。我应该在主线程上运行完成块。但问题不在于此。