2

我在测试中没有遇到任何崩溃,但我从 iTunesConnect 获得了一些崩溃报告,如下所示:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x45d319f8
Crashed Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x3a6595be objc_msgSend + 30
1   UIKit                           0x34796e30 -[UIImageView setImage:] + 116
2   My App                      0x000c40b2 -[AsyncImageView setImage:] (AsyncImageView.m:224)
3   My App                      0x000c3950 __47-[AsyncImageView loadImageWithURL:animated:]_block_invoke_2 (AsyncImageView.m:147)

AsyncImageView 是一个典型的 UIImageView 子类,它从 URL 异步加载图像。

这是带有违规行号的资产加载代码:

- (void)loadImageWithURL:(NSURL *)url animated:(BOOL)animated {

    if (url == nil) {
        [self setImage:nil];
        return;
    }

    self.imageAsset = [[Asset alloc] init];
    self.imageAsset.assetURL = url;

    AssetRequest *request = [[AssetRequest alloc] init];
    request.assetURL = url;

    __weak AsyncImageView *weakSelf = self;
    self.assetLoader = [AssetLoader AssetLoaderWithRequest:request
                                                 completion:^(Asset *asset){
                                                    dispatch_async(dispatch_get_main_queue(), ^{

                                                    if (weakSelf.imageAsset.assetURL == asset.assetURL) {

                                                             weakSelf.imageAsset = asset;

                                                             if (animated) {
                                                                 CATransition *transition = [CATransition animation];
                                                                 transition.type = kCATransitionFade;
                                                                 transition.duration = 0.20;
                                                                 [weakSelf.layer addAnimation:transition forKey:nil];
                                                             }

                                                            [weakSelf setImage:weakSelf.imageAsset.assetImage]; //THIS IS LINE 147


                                                             [weakSelf setDisplayLoadingIndicator:NO];
                                                             [weakSelf stopAnimating];
                                                    }

                                                    });
                                                 }
                                                     error:^(NSError *err){

                                                         if (weakSelf.failedToLoad)
                                                             weakSelf.failedToLoad(url);

                                                     }];

    [self.assetLoader load];
}

这是设置图像的位置,并指示了违规行号:

- (void)setImage:(UIImage *)image {

        if (image) {
            [super setImage:image]; //THIS IS LINE 224
            [self hidePlaceholderView];

            if (self.imageLoadedBlock)
                self.imageLoadedBlock();
        }
        else {
            [self showPlaceholderView];
        }

    }

崩溃报告表明设置图像时发生崩溃。是否有任何明显的原因导致这种情况发生?或者我可以做的任何进一步的错误检查(我已经在检查图像不为空)?再说一次,这种情况不会一直发生,只会偶尔发生一次。

4

2 回答 2

0

问题是您正在使用走动进行保留周期:

    __weak AsyncImageView *weakSelf = self;

使用这种方法,它不会被块保留 - 因此,如果有人在执行块之前足够快地离开 - selfBlock 会被释放。

最好的办法是取消对 dealloc 的所有操作,或者至少将完成块设置为“nil”。

- (void) dealloc
{
    [self.assetLoader cancelAllOperations]; //of course you need to implement that
    [super dealloc];
}

我认为如果您对应用程序进行压力测试并在边缘连接上使用它并在响应到来之前非常快速地离开视图,您将能够重现这一点。

另一个更简单的解决方案是不将“AssetLoader”保留为属性,并远程将此 __block 变量让块保留“self”。但是当视图不在屏幕上并且将被更新时,它可能会导致意外行为。

于 2013-09-10T16:41:43.780 回答
0

我查看了 SDWebImage 源代码,当资产加载器完成时,它们会执行以下操作:

if (!weakSelf) {
   return;
}

dispatch_async(dispatch_get_main_queue(), ^{
   if (weakSelf.imageAsset.assetURL == asset.assetURL) {
      weakSelf.imageAsset = asset;
      [weakSelf setImage:weakSelf.imageAsset.assetImage];
       ...
    }                                                         
 });

所以基本上如果weakSelf 不再存在,什么都不做。问自己是否仍然存在似乎有点奇怪,但这会解决问题吗?

于 2013-09-10T17:41:43.817 回答