0

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

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

通过长距离滚动,每个图块都有多次重绘:每个图块在显示正确的图块之前先加载(并显示)不同的图像几次。

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

我继承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: > 取消的LoadImage方法: 在执行isCancelled: >

因此取消工作。

现在我保存对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 

非常感谢任何帮助!

SOLUTION:

从回答如下:需要从的NSOperation

子类

当我子类的NSOperation,并把所有的LoadImage:代码到它的“主”的方法(只是将所有代码在这里,没有别的),所有的工作都很完美!

随着对滚动延迟:它发生的原因加载图像到UIImageView的(需要很长的时间,因为解压缩和光栅化的(我的理解)

因此,更好的办法是使用CATiledLayer它在后台加载数据和。做得更快

回答

1

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

+0

但即使从缓存文件加载数据并且根本不使用网络,也会出现缓慢滚动。在特定线程中的所有数据加载管理NSOperationQueue。如果我将从NSOperation子类创建另一个新线程,它可以帮助吗? – 2012-03-17 12:44:12

+0

可能有太多的线程...尝试设置队列中并发操作的最大数量,看看发生了什么 – Andrea 2012-03-17 18:09:49

+0

忘了说也尝试使用核心动画工具和时间分析器来检查性能,看看是否有长时间操作。 – Andrea 2012-03-17 18:11:14

1

NSOperationQueue对于“setSuspended”的工作方式是它不会开始运行新添加的NSOperations,并且不会开始运行当前所有的尚未开始运行。您确定要取消的操作尚未开始吗?

另外 - 您的NSOperation子类是否正确处理关键值观察?并发队列子类NSOperations必须呼叫willChangeValueForKeydidChangeValueForKey对于某些属性here - 但看起来不像这是问题,因为您的队列未设置isConcurrent。只是FYI,如果你走这条路。

+0

我不确定它还没有开始。正是为了这个,我检查了isCancelled在target的方法中取消了已经开始的操作。子类只添加上下文变量,什么都不做。它仍然需要重新定义NSOperation的所有员工?是的。我不使用并发,它可以帮助,如果我会用? – 2012-03-17 12:29:47

+0

当然 - 但isCancelled是一个KVO属性 - 在你的子类中添加一个NSLog()语句,当方法启动时打印出一个ID或某个东西,并且可以将它与isCancelled检查相关联。 – 2012-03-17 12:32:41

+0

不清楚明白...添加NSLog到loadImage:?为了什么? – 2012-03-17 13:03:08