NSOperationQueue 取消特定操作 [英] NSOperationQueue cancel specific operations

查看:92
本文介绍了NSOperationQueue 取消特定操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The problem is that I manage scrollView with lots of tiles in it. Each visible tile display image loaded from URL or (after first URL load) cached file in background. Invisible tiles recycles (set new frame and redraw).

图像加载取决于图块位置.

Image load depends on tile position.

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

With long range scroll there is multiple redraw called for each tile: each tile loads (and display) different image several times before display the correct one.

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

So problem is to cancel all previously added operations for tile before add new.

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

I subclass NSInvocationOperation just to contain context object to detect operation attached to and before add new operation I canceling all operation for same tile:

 -(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:

And in operation itself I check 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];

    }

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

But it is do nothing. Some times early returns works but tiles still load many images before the correct one.

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

更新:

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

With NSLog: isCancelled while executing: > cancel loadImage method for: >

所以取消工作.

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

Now I save reference to last operation in TileView object and perform setImage operation only if invoked operation is equal to TileView operation.

没有任何区别...

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

Looks like there IS number of operations to load different images to one tile invoked one after another.

还有什么建议吗?

清关:

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

There is singleton DataLoader (all code from it). And all tiles has call to it in drowRect:

[[DataLoader sharedDataLoader] loadWithColler:self];

更新:

NSInvocationOperation 子类:

NSInvocationOperation subclass:

@interface NSInvocationOperationWithContext : NSInvocationOperation {
    id context;
}

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

@end


@implementation NSInvocationOperationWithContext

@synthesize context;


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

非常感谢任何帮助!

解决方案:

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

From answer below: need to subclass from NSOperation

当我继承 NSOperation 并将所有 loadImage: 代码放入它的main"方法中时(只需将所有代码移到此处,不要移动其他任何代码),并且一切正常!

As I subclass NSOperation and put all loadImage: code into it "main" method (just move all code here and nothing else) and all work just perfect!

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

As about scroll delaying: it occurs cause loading images to UIImageView (it takes long time because of decompress and rasterize (as I understood).

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

So better way is to use CATiledLayer. It loads data in background and do it much faster.

推荐答案

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

The delays on main thread is due to a the mode of the runloop while you scroll. I suggest you to watch the WWDC2011 networking app sessions. I don't know if it is fine to subclass an NSInvocationOperation that is a concrete subclass of NSOperation. I will subclass NSOperation instead. For my experience if you like to avoid sluggish scrolling, you should create NSOperation subclasses that load their main on a specific thread for networking operation (you must create it). There is a wonderful sample code from apple https://developer.apple.com/library/ios/#samplecode/MVCNetworking/Introduction/Intro.html

这篇关于NSOperationQueue 取消特定操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆