【问题标题】:NSOperationQueue cancel specific operationsNSOperationQueue 取消特定操作
【发布时间】:2012-03-17 11:41:31
【问题描述】:

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

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

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

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

我将 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。它在后台加载数据并且速度更快。

【问题讨论】:

    标签: ios multithreading nsoperationqueue nsinvocationoperation


    【解决方案1】:

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

    【讨论】:

    • 但是即使从缓存文件加载数据并且根本不使用网络,也会出现缓慢的滚动。在特定线程管理的 NSOperationQueue 中加载所有数据。如果我要从 NSOperation 子类创建另一个新线程会有帮助吗?
    • 可能线程太多了...尝试设置队列中的最大并发操作数,看看会发生什么
    • 忘了说也试试用核心动画工具和时间分析器检查性能,看看是否有任何长时间的操作。
    【解决方案2】:

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

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

    【讨论】:

    • 我不确定它还没有开始。正是为此,我检查了目标方法中的 isCancelled 以取消已经开始的操作。子类只添加上下文变量,什么都不做。它还需要重新定义所有 NSOperation 的人员吗?是的。我不使用并发,如果我会使用它会有所帮助吗?
    • 当然——但是 isCancelled 是一个 KVO 属性——在你的子类中添加一个 NSLog() 语句,当方法启动时打印出一个 ID 或其他东西,你可以将它与你的 isCancelled 检查相关联。跨度>
    • 不是很清楚... 添加NSLog到loadImage:?为了什么?
    • 用你无法控制的线程来检查基于 GCD 的状态是很棘手的。将日志行添加到您在启动/取消时创建的 NSOperation 子类中,以便您了解线程间到底发生了什么会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2020-04-19
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    相关资源
    最近更新 更多