![](/img/trans.png)
[英]iOS Swift - How to reference a NSOperationQueue in an extension to cancel existing operations?
[英]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 必须为这里的某些属性调用willChangeValueForKey
和didChangeValueForKey
- 但看起来不是问题,因为您的队列没有设置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.