gpt4 book ai didi

iphone - 将 block 与 NSOperation 一起使用

转载 作者:行者123 更新时间:2023-11-29 13:16:34 24 4
gpt4 key购买 nike

这是 this post 的延续.我的 NSOperation block 有问题,我的应用程序在 completionblock 中崩溃。

我认为问题是一个保留周期(我有一个警告:在此 block 中强烈捕获 self 可能会导致保留周期),我尝试 this solution (见上面的代码),警告消失了,但应用程序仍然崩溃。

应用程序是一个简单的 tableView。该操作对传递的图像进行一些修改。

这是我第一次自己创建和使用 block ,谢谢你给我一些基本的解释

代码:

TableViewController.m:

在 tableView 中:cellForRowAtIndexPath:

   [[ImageManager sharedManager] modifyImage:[UIImage imageNamed:@"anImage.png"] completionBlock:^(UIImage *image, NSError *error) {        
[cell.imageView setImage:image];
}];

ImageManager.h:

  #import <Foundation/Foundation.h>
@interface ImageManager : NSObject
@property(nonatomic, strong) NSOperationQueue *imageOperationQueu;

-(void) modifyImage:(UIImage*)image completionBlock:(void(^)(UIImage *image,NSError *error)) completBlock;

+ (id) sharedManager;

@end

ImageManager.m:

#import "ImageManager.h"
#import "ImageOperations.h"

static ImageManager *MySharedManager = nil;

@implementation ImageManager

@synthesize imageOperationQueu;

+ (id)sharedManager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (MySharedManager == nil) MySharedManager = [[self alloc] init];
});
return MySharedManager;
}

- (NSOperationQueue *)imageOperationQueu
{
if (!imageOperationQueu)
{
imageOperationQueu = [[NSOperationQueue alloc] init];
[imageOperationQueu setMaxConcurrentOperationCount:3];
imageOperationQueu.name = @"imageOperationQueu";
}
return imageOperationQueu;
}

-(void) modifyImage:(UIImage*)image completionBlock:(void(^)(UIImage *image,NSError *error)) completBlock
{
ImageOperations *op = [[ImageOperations alloc]initWithImage:image WithCompletionBlock:completBlock];
[self.imageOperationQueu addOperation:op];
}
@end

ImageOperations.h:

 #import <Foundation/Foundation.h>

typedef void (^CompletionBlock)(UIImage *image,NSError *error);

@interface ImageOperations : NSOperation

@property(nonatomic, weak) CompletionBlock completBlock;
@property(nonatomic, strong) UIImage *imageToTransform;

-(id)initWithImage:(UIImage *)image WithCompletionBlock:(CompletionBlock) block;
@end

ImageOperations.m:

 #import "ImageOperations.h"

@implementation ImageOperations
@synthesize imageToTransform;
@synthesize completBlock;

-(id)initWithImage:(UIImage *)image WithCompletionBlock:(CompletionBlock) block
{
if (self = [super init])
{
NSLog(@"initWithImage");
self.imageToTransform = image;
[self setCompletBlock:block];
}
return self;
}

- (void)main
{
@autoreleasepool
{
UIImage *img = [self setRoundedImage:self.imageToTransform];

__weak ImageOperations *imgOp = self;

[imgOp setCompletionBlock:^{
NSLog(@"setCompletionBlock");
imgOp.completBlock(img,nil);
}];
}
}

-(UIImage*)setRoundedImage:(UIImage*)image
{
// ..
}

@end

最佳答案

几个想法:

  1. 您将 block 定义为 weak 属性。在Working With Blocks Programming with Objective-C 指南的部分建议您改用copy。 (注意,我们复制的是 block ,而不是它使用的对象;不过,您必须注意该 block 内的强引用。) block 变量的范围非常微妙。 (请参阅 Block Programming Topics 指南中的 Patterns to Avoid 以获取示例。)调用因 weak 而发布的 block 可以生成一些不可预测的结果。使用复制

  2. 您的 tableview 有一个微妙的问题,如果在调用完成 block 时单元格已经滚动,将会发生什么。该单元格可以重新用于表格的另一行。 (事实证明,圆角逻辑可能足够快,这个问题不太可能自己显现出来,但如果您执行较慢的操作(例如下载图像或图像很大),这很关键。)无论如何,而不是:

    [[ImageManager sharedManager] modifyImage:[UIImage imageNamed:@"anImage.png"] completionBlock:^(UIImage *image, NSError *error) {        
    [cell.imageView setImage:image];
    }];

    您可能想调用 UITableView 方法 cellForRowAtIndexPath(不要与 UITableViewController 方法 tableView:cellForRowAtIndexPath:):

    [[ImageManager sharedManager] modifyImage:[UIImage imageNamed:@"anImage.png"] completionBlock:^(UIImage *image, NSError *error) {   
    if (error == nil)
    {
    UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];

    // if cell has scrolled off screen, this will be `nil`, so let's check

    if (updateCell)
    [updateCell.imageView setImage:image];
    }
    }];
  3. 您可能需要注意 imageNamed 方法本身在第一次检索图像时可能很慢的事实。如果所有单元格都返回相同的 imageNamed,这不是问题,但如果 (a) 使用唯一的 imageNamed 文件; (b) 如果处理较旧、较慢的设备,您甚至可能希望将 imageNamed 进程也插入后台队列。在较新的设备上(或在模拟器上),你永远不会看到这个问题,但如果你在一个旧的、慢速的设备上测试,你可能会看到快速的 tableview 滚动中有些卡顿(但因为 imageNamed缓存,您只会在首次检索图像时看到这个断断续续的 UI...如果您对所有图像使用相同的图像名称,您可能看不到这一点。)

  4. 您对 completBlock 的调用正在后台队列中完成。由于您正在进行 UI 更新,因此您可能希望确保将其分派(dispatch)回主队列:

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
    // call the completBlock here
    }];

关于iphone - 将 block 与 NSOperation 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15660684/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com