代码之家  ›  专栏  ›  技术社区  ›  Jukurrpa

ASIHTTPRequest dealloc和EXC\u BAD\u访问问题

  •  2
  • Jukurrpa  · 技术社区  · 14 年前

    我正在使用ASIHTTPRequest包装器数组(AsyncImageLoader)下载UITableView中单元格的图像。

    我在处理ASIHTTPRequests时遇到了问题。如果我释放它们,如果我在它们试图加载图像时不断上下滚动,我最终会有一个EXC\u BAD\u访问权限。

    我的包装纸是这样的。 self.request 保留财产, targetCell 是我要将图像放入的单元格:

    @implementation AsyncImageLoader
    - (void)loadImageFromURL:(NSString*)fileName target:(ResultTableViewCell*)targetCell {
        // check for cached images, etc
    
        NSURL* url = [NSURL URLWithString:fileName];
        [self.request cancel];
        self.request = [ASIHTTPRequest requestWithURL:url];
        self.request.delegate = self;
    }
    
    - (void)startLoading {
        [self.request startAsynchronous];
    }
    
    - (void)cancel {
        [self.request cancel];
        self.request = nil;
    }
    
    - (void)requestFinished:(ASIHTTPRequest*)requestDone {
        // cache image, set cell image...
    
        self.request = nil;
    }
    
    - (void)requestFailed:(ASIHTTPRequest*)requestDone {
        // handle answer as well
    
        self.request = nil;
    }
    @end
    

    loadImageFromURL 被召入 cellForRowAtIndexPath indexPath.row % 6 因此,如果我一直上下滚动,它会被同一个对象反复调用,取消请求,因为它们还没有结束。

    但我最后总是有一个例外。根据调用堆栈,它发生在ASIHTTPRequest的 markAsFinished failWithError ,由调用 [self.request cancel] loadImageFromURL:

    如果我删除了 self.request = nil 在委托方法中,但是由于ASIHTTPRequests在没有释放的情况下不断被创建,它们最终无法工作。

    4 回复  |  直到 14 年前
        1
  •  5
  •   Matt Long    14 年前

    当你遇到一个问题,你得到EXC\u BAD\u访问它意味着你发布了一些东西。在大多数情况下,只需运行调试器(Command-Y)并查看 你的代码 当它崩溃时,在堆栈跟踪中找出哪个对象被过度释放。如果这不管用,那你就得 turn on zombies

    顺便说一句,还有一些其他的库可以做你想做的事情。我没怎么用过这个,但看起来它至少有潜力。退房: SDWebImage

    致以最诚挚的问候。

        2
  •  2
  •   JosephH    14 年前

    我还不确定是什么原因导致它,但我坚信它与客户端代码无关(即,它要么在ASIHTTPRequest中,要么在OS中)。

    我一直在苹果论坛上寻求帮助:

    https://devforums.apple.com/thread/59843?tstart=0

    以下是坠机对我的影响:

    #2  0x32c02e14 in CFRetain ()
    #3  0x32c709b6 in __CFTypeCollectionRetain ()
    #4  0x32c06c60 in _CFArrayReplaceValues ()
    #5  0x32b0994c in -[NSCFArray insertObject:atIndex:] ()
    #6  0x32b098f0 in -[NSCFArray addObject:] ()
    #7  0x32b709f0 in __chooseAll ()
    #8  0x32b71bde in __finishedOp ()
    #9  0x32b26636 in +[NSOperation observeValueForKeyPath:ofObject:change:context:] ()
    #10 0x32b265aa in NSKVONotify ()
    #11 0x32b13306 in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
    #12 0x0007d6ec in -[ASIHTTPRequest markAsFinished] (self=0x5a7cc40, _cmd=0xa1710) at ASIHTTPRequest.m:2817
    #13 0x00077e02 in -[ASIHTTPRequest failWithError:] (self=0x5a7cc40, _cmd=0x330cdfc4, theError=0x248130) at ASIHTTPRequest.m:1708
    #14 0x000712dc in -[ASIHTTPRequest cancel] (self=0x5a7cc40, _cmd=0x322b4298) at ASIHTTPRequest.m:515
    #15 0x0008884c in -[UIHTTPImageView setImageWithURL:placeholderImage:] (self=0x5a7c9d0, _cmd=0xa3f0c, url=0x5aa7760, placeholder=0x0) at UIHTTPImageView.m:21
    #16 0x0006183c in -[MeetingView tiledScrollView:tileForRow:column:resolution:] (self=0x5a32560, _cmd=0x9bfac, tiledScrollView=0x5a74570, row=1, column=0, resolution=0) at MeetingView.m:1053
    #17 0x0000475e in -[TiledScrollView layoutSubviews] (self=0x5a74570, _cmd=0x32299680) at TiledScrollView.m:181
    #18 0x31515f32 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:] ()
    #19 0x32c29ffa in -[NSObject performSelector:withObject:] ()
    #20 0x30964798 in -[CALayer layoutSublayers] ()
    #21 0x30964568 in CALayerLayoutIfNeeded ()
    #22 0x30959b62 in CA::Context::commit_transaction ()
    #23 0x3095997a in CA::Transaction::commit ()
    #24 0x3097f164 in CA::Transaction::observer_callback ()
    #25 0x32c702a0 in __CFRunLoopDoObservers ()
    #26 0x32c23bb0 in CFRunLoopRunSpecific ()
    #27 0x32c234e0 in CFRunLoopRunInMode ()
    #28 0x30d620da in GSEventRunModal ()
    #29 0x30d62186 in GSEventRun ()
    #30 0x314d54c8 in -[UIApplication _run] ()
    #31 0x314d39f2 in UIApplicationMain ()
    #32 0x0000245c in main (argc=1, argv=0x2ffff5b4) at main.m:14
    

    据我所知,这些动作是这样的:

    1. 请求在开始运行前被取消
    2. 另一个请求完成,并且队列中的调用保留在释放的请求上

    有可能ASIHTTPRequest仍然错误地处理了cancel请求,但是我发现很难理解如何处理。

    更新

    这应该可以解决:

    http://github.com/jogu/asi-http-request/commit/887fcad0f77e9717f003273612804a9b9012a140

        3
  •  1
  •   Jukurrpa    14 年前

    对自己的回答是我的结论和其他答案的综合。

    在取消请求时,ASIHTTPRequest(或者iOS)似乎有点不稳定,特别是当有多个请求并且许多请求被取消并很快发布时。

    作为一个解决方案,我放弃了创建许多请求并在不再需要它们时取消它们的设计。我做了个包装 ASIHTTPRequest 在一个 NSOperationQueue ,它还过滤url,这样同一请求就不会启动两次(如果出现单元格,则在图像完全加载之前消失,然后再次显示)。我将所有请求结果(即图像)存储在缓存中。

    这可能会导致网络活动稍微增加,但随着每个新请求的完成(即使图像可能没有显示)和缓存,其他一切都会变得更加清晰,因此不需要处理创建/取消等操作。。。因此不会再有崩溃。

        4
  •  0
  •   scurioni    12 年前

    尝试在视图的dealloc中添加类似的内容:

        [self.thumbnailRequest cancel];
    self.thumbnailRequest.delegate = nil;
    [self.thumbnailRequest setDidFinishSelector:NULL];
    [self.thumbnailRequest setDidFailSelector:NULL];
    self.thumbnailRequest = nil;