有时应用程序在 SDWebImage 中崩溃(SDWebImageDownloaderOperation#cancelInternal)
Sometimes app crash in SDWebImage(SDWebImageDownloaderOperation#cancelInternal)
我们在我们的应用程序上使用了 SDWebImage Lib。(SDWebImage 版本 3.7.2)
最近,应用程序有时会异常终止。(在 SDWebImageDownloaderOperation#cancelInternal.)
以下是堆栈跟踪。
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0xxx
Thread : Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x180765bd0 objc_msgSend + 16
1 HOGE 0x1002a94d8 -SDWebImageDownloaderOperation cancelInternal
2 HOGE 0x1002a93ec -SDWebImageDownloaderOperation cancel
3 HOGE 0x1002ad63c __69-[SDWebImageManager downloadImageWithURL:options:progress:completed:]_block_invoke131 (SDWebImageManager.m:245)
4 HOGE 0x1002ae0f0 -SDWebImageCombinedOperation cancel
5 HOGE 0x1002b5380 -UIView(WebCacheOperation) sd_cancelImageLoadOperationWithKey:
6 HOGE 0x1002b0c74 -UIButton(WebCache) sd_cancelImageLoadForState:
7 HOGE 0x1002af578 -UIButton(WebCache) sd_setImageWithURL:forState:placeholderImage:options:completed:
8 HOGE 0x1002af3f8 -UIButton(WebCache) sd_setImageWithURL:forState:placeholderImage:options:
中止点如下。
[imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
(它叫做 Collection view cell 的 layoutSubviews)
Collection查看单元格的查看源代码。
Header
#import <UIKit/UIKit.h>
#import "Photo.h"
@interface PhotoCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIButton *imageButton;
@property (strong, nonatomic) UIButton *likeButton;
@property (strong, nonatomic) Photo *photo;
@end
实施
@implementation PhotoCollectionViewCell
- (void)awakeFromNib
{
self.selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
self.selectedBackgroundView.backgroundColor = [BaseColorSet getColor1];
[_imageButton setBackgroundColor:[BaseColorSet getPhotoBackgroundColor]];
_imageButton.layer.cornerRadius = 2;
_imageButton.clipsToBounds = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
NSString *url = [PhotoImgURL get_5:_photo];
if (!url) {
url = [NSString stringWithFormat:@"%@/%@/%@",S3_STORAGE_URL,[PhotoDirectory get_5],_photo.filename];
}
[_imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
_imageButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
_imageButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
_imageButton.imageView.contentMode = UIViewContentModeScaleToFill;
}
@end
我的CollectionViewController
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCollectionViewCell *cell = (PhotoCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.photo = [_photos objectAtIndex:indexPath.row];
[cell.imageButton addTarget:self action:@selector(imageButtonPushed:) forControlEvents:UIControlEventTouchUpInside];
[cell setNeedsLayout];
// add Load processing
if (indexPath.row == _photos.count-1 && !_isLast) {
Photo *photo = [_photos objectAtIndex:indexPath.row];
[self pagingMyView:photo];
}
return cell;
}
为什么异常终止?
我应该如何避免这个错误?
(是坏存取内存吗?)
编辑
谢谢。
暂未发布,修改代码如下
照片CollectionViewCell(固定。)
@implementation PhotoCollectionViewCell
- (void)awakeFromNib
{
self.selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
self.selectedBackgroundView.backgroundColor = [BaseColorSet getColor1];
[_imageButton setBackgroundColor:[BaseColorSet getPhotoBackgroundColor]];
_imageButton.layer.cornerRadius = 2;
_imageButton.clipsToBounds = YES;
_imageButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
_imageButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
_imageButton.imageView.contentMode = UIViewContentModeScaleToFill;
}
-(void)prepareForReuse
{
[super prepareForReuse];
[_imageButton sd_cancelImageLoadForState:UIControlStateNormal];
}
@end
我的CollectionViewController(固定)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCollectionViewCell *cell = (PhotoCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.photo = [_photos objectAtIndex:indexPath.row];
cell.imageButton.tag = cell.photo.photoId;
NSString *url = [PhotoImgURL get_5:cell.photo];
if (!url) {
url = [NSString stringWithFormat:@"%@/%@/%@",S3_STORAGE_URL,[PhotoDirectory get_5],cell.photo.filename];
}
[cell.imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
[cell.imageButton addTarget:self action:@selector(imageButtonPushed:) forControlEvents:UIControlEventTouchUpInside];
[cell setNeedsLayout];
// add Load processing
if (indexPath.row == _photos.count-1 && !_isLast) {
Photo *photo = [_photos objectAtIndex:indexPath.row];
[self pagingMyView:photo];
}
return cell;
}
在UITableViewCell 和UICollectionViewCell 中使用SDWebImageView 或SDWebImageButton 时,您必须注意'cell's reuse timing' 和'asynchronous download and set image timing'。
快速滚动时会发生这种情况,因此当异步下载完成时,ui 已被另一个单元格重用。
为了避免这个错误(我猜),
在
中使用 SDWebImage api
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
或
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
并用'__block'
获取UI的指针
如果您提供更多关于 'cellForItemAtIndexPath' 的代码,我可以帮助您。
我们在我们的应用程序上使用了 SDWebImage Lib。(SDWebImage 版本 3.7.2) 最近,应用程序有时会异常终止。(在 SDWebImageDownloaderOperation#cancelInternal.)
以下是堆栈跟踪。
Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0xxx Thread : Crashed: com.apple.main-thread 0 libobjc.A.dylib 0x180765bd0 objc_msgSend + 16 1 HOGE 0x1002a94d8 -SDWebImageDownloaderOperation cancelInternal 2 HOGE 0x1002a93ec -SDWebImageDownloaderOperation cancel 3 HOGE 0x1002ad63c __69-[SDWebImageManager downloadImageWithURL:options:progress:completed:]_block_invoke131 (SDWebImageManager.m:245) 4 HOGE 0x1002ae0f0 -SDWebImageCombinedOperation cancel 5 HOGE 0x1002b5380 -UIView(WebCacheOperation) sd_cancelImageLoadOperationWithKey: 6 HOGE 0x1002b0c74 -UIButton(WebCache) sd_cancelImageLoadForState: 7 HOGE 0x1002af578 -UIButton(WebCache) sd_setImageWithURL:forState:placeholderImage:options:completed: 8 HOGE 0x1002af3f8 -UIButton(WebCache) sd_setImageWithURL:forState:placeholderImage:options:
中止点如下。
[imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
(它叫做 Collection view cell 的 layoutSubviews)
Collection查看单元格的查看源代码。 Header
#import <UIKit/UIKit.h>
#import "Photo.h"
@interface PhotoCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIButton *imageButton;
@property (strong, nonatomic) UIButton *likeButton;
@property (strong, nonatomic) Photo *photo;
@end
实施
@implementation PhotoCollectionViewCell
- (void)awakeFromNib
{
self.selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
self.selectedBackgroundView.backgroundColor = [BaseColorSet getColor1];
[_imageButton setBackgroundColor:[BaseColorSet getPhotoBackgroundColor]];
_imageButton.layer.cornerRadius = 2;
_imageButton.clipsToBounds = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
NSString *url = [PhotoImgURL get_5:_photo];
if (!url) {
url = [NSString stringWithFormat:@"%@/%@/%@",S3_STORAGE_URL,[PhotoDirectory get_5],_photo.filename];
}
[_imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
_imageButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
_imageButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
_imageButton.imageView.contentMode = UIViewContentModeScaleToFill;
}
@end
我的CollectionViewController
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCollectionViewCell *cell = (PhotoCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.photo = [_photos objectAtIndex:indexPath.row];
[cell.imageButton addTarget:self action:@selector(imageButtonPushed:) forControlEvents:UIControlEventTouchUpInside];
[cell setNeedsLayout];
// add Load processing
if (indexPath.row == _photos.count-1 && !_isLast) {
Photo *photo = [_photos objectAtIndex:indexPath.row];
[self pagingMyView:photo];
}
return cell;
}
为什么异常终止?
我应该如何避免这个错误?
(是坏存取内存吗?)
编辑
谢谢。 暂未发布,修改代码如下
照片CollectionViewCell(固定。)
@implementation PhotoCollectionViewCell
- (void)awakeFromNib
{
self.selectedBackgroundView = [[UIView alloc] initWithFrame:self.bounds];
self.selectedBackgroundView.backgroundColor = [BaseColorSet getColor1];
[_imageButton setBackgroundColor:[BaseColorSet getPhotoBackgroundColor]];
_imageButton.layer.cornerRadius = 2;
_imageButton.clipsToBounds = YES;
_imageButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
_imageButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
_imageButton.imageView.contentMode = UIViewContentModeScaleToFill;
}
-(void)prepareForReuse
{
[super prepareForReuse];
[_imageButton sd_cancelImageLoadForState:UIControlStateNormal];
}
@end
我的CollectionViewController(固定)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
PhotoCollectionViewCell *cell = (PhotoCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.photo = [_photos objectAtIndex:indexPath.row];
cell.imageButton.tag = cell.photo.photoId;
NSString *url = [PhotoImgURL get_5:cell.photo];
if (!url) {
url = [NSString stringWithFormat:@"%@/%@/%@",S3_STORAGE_URL,[PhotoDirectory get_5],cell.photo.filename];
}
[cell.imageButton sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:nil options:SDWebImageRetryFailed];
[cell.imageButton addTarget:self action:@selector(imageButtonPushed:) forControlEvents:UIControlEventTouchUpInside];
[cell setNeedsLayout];
// add Load processing
if (indexPath.row == _photos.count-1 && !_isLast) {
Photo *photo = [_photos objectAtIndex:indexPath.row];
[self pagingMyView:photo];
}
return cell;
}
在UITableViewCell 和UICollectionViewCell 中使用SDWebImageView 或SDWebImageButton 时,您必须注意'cell's reuse timing' 和'asynchronous download and set image timing'。
快速滚动时会发生这种情况,因此当异步下载完成时,ui 已被另一个单元格重用。
为了避免这个错误(我猜),
在
中使用 SDWebImage api- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
或
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
并用'__block'
获取UI的指针如果您提供更多关于 'cellForItemAtIndexPath' 的代码,我可以帮助您。