繁体   English   中英

NSOperationQueue 取消特定操作

[英]NSOperationQueue cancel specific operations

问题是我管理的 scrollView 中有很多图块。 每个可见图块显示从 URL 加载的图像或(在第一次 URL 加载后)后台缓存文件。 隐形瓷砖回收(设置新框架并重绘)。

图像加载取决于平铺位置。

对于长距离滚动,每个图块都会调用多次重绘:每个图块在显示正确的图像之前多次加载(并显示)不同的图像。

所以问题是在添加新之前取消所有先前添加的 tile 操作。

我子类化 NSInvocationOperation 只是为了包含上下文对象来检测附加到的操作,在添加新操作之前我取消了同一个图块的所有操作:

 -(void)loadWithColler:(TileView *)coller {    
    if (queue == nil) {
        queue = [NSOperationQueue new];
    }

    NSInvocationOperationWithContext *loadImageOp = [NSInvocationOperationWithContext alloc];
    [loadImageOp initWithTarget:self selector:@selector(loadImage:) object:loadImageOp];
    [loadImageOp setContext:coller];

    [queue setSuspended:YES];
    NSArray *opers = [queue operations];
    for (NSInvocationOperationWithContext *nextOperation in opers) {

        if ([nextOperation context] == coller) {
            [nextOperation cancel];
        }

    }

    [queue addOperation:loadImageOp]; 
    [queue setSuspended:NO];    
    [loadImageOp release];
}

在操作本身中,我检查 isCancelled:

    -(void)loadImage:(NSInvocationOperationWithContext *)operation {

        if (operation.isCancelled) return;

        TileView *coller = [operation context];

        /* TRY TO GET FILE FROM CACHE */    
        if (operation.isCancelled) return;

        if (data) {

            /* INIT WITH DATA IF LOADED */

        } else {
            /* LOAD FILE FROM URL AND CACHE IT */
        }

        if (operation.isCancelled) return;

        NSInvocationOperation *setImageOp = [[NSInvocationOperation alloc] initWithTarget:coller selector:@selector(setImage:) object:cachedImage];
        [[NSOperationQueue mainQueue] addOperation:setImageOp];
        [setImageOp release];

    }

但它什么都不做。 有时提前返回有效,但图块仍会在正确的图像之前加载许多图像。

那我怎么能成功呢? 滚动时这么多不需要的操作会导致主线程延迟吗? (因为存在延迟,我不知道为什么......所有在后台加载......)

更新:

使用 NSLog: isCancelled 执行时: > 取消 loadImage 方法: >

所以取消工作。

现在我保存对 TileView 对象中最后一个操作的引用,并且仅当调用的操作等于 TileView 操作时才执行 setImage 操作。

没什么区别...

看起来有很多操作可以将不同的图像加载到一个接一个调用的图块。

还有其他建议吗?

清关:

有单例 DataLoader(来自它的所有代码)。 并且所有图块都在 drowRect 中调用它:

[[DataLoader sharedDataLoader] loadWithColler:self];

更新:

NSInvocationOperation 子类:

@interface NSInvocationOperationWithContext : NSInvocationOperation {
    id context;
}

@property (nonatomic,retain,readwrite) id context;

@end


@implementation NSInvocationOperationWithContext

@synthesize context;


- (void)dealloc
{
    [context release];
    [super dealloc];
}
@end

非常感谢您帮助!

解决方案:

从下面的答案:需要从 NSOperation 子类化

当我继承 NSOperation 并将所有 loadImage: 代码放入它的“main”方法中时(只需将所有代码移到此处而没有其他任何内容),并且所有工作都非常完美!

至于滚动延迟:它发生导致将图像加载到 UIImageView (由于解压缩和光栅化(据我所知)需要很长时间)。

所以更好的方法是使用 CATiledLayer。 它在后台加载数据并且加载速度更快。

NSOperationQueue 与“setSuspended”相关的工作方式是它不会开始运行在那之后添加到它的新添加的 NSOperations,并且不会开始运行任何当前在其中但尚未开始运行的NSOperations . 您确定您要取消的操作尚未开始吗?

另外 - 您的 NSOperation 子类是否正确处理键值观察? 并发队列子类 NSOperations 必须为这里的某些属性调用willChangeValueForKeydidChangeValueForKey - 但看起来不是问题,因为您的队列没有设置isConcurrent 如果你走那条路,仅供参考。

主线程的延迟是由于滚动时运行循环的模式。 我建议您观看 WWDC2011 网络应用程序会议。 我不知道将NSInvocationOperation子类化是否可以,它是NSOperation的具体子类。 我将NSOperation 根据我的经验,如果您想避免缓慢滚动,您应该创建NSOperation子类,将它们的主要加载到特定线程以进行网络操作(您必须创建它)。 苹果有一个很棒的示例代码https://developer.apple.com/library/ios/#samplecode/MVCNetworking/Introduction/Intro.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM