Iphone 将NSO操作子类化为并发且可取消
我找不到关于如何将Iphone 将NSO操作子类化为并发且可取消,iphone,nsoperation,nsoperationqueue,performselector,Iphone,Nsoperation,Nsoperationqueue,Performselector,我找不到关于如何将NSOperation子类化为并发并支持取消的好文档。我读了苹果的文档,但找不到“官方”的例子 以下是我的源代码: @synthesize isExecuting = _isExecuting; @synthesize isFinished = _isFinished; @synthesize isCancelled = _isCancelled; - (BOOL)isConcurrent { return YES; } - (void)start { /* WHY
NSOperation
子类化为并发并支持取消的好文档。我读了苹果的文档,但找不到“官方”的例子
以下是我的源代码:
@synthesize isExecuting = _isExecuting;
@synthesize isFinished = _isFinished;
@synthesize isCancelled = _isCancelled;
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
/* WHY SHOULD I PUT THIS ?
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
*/
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
if (_isCancelled == YES)
{
NSLog(@"** OPERATION CANCELED **");
}
else
{
NSLog(@"Operation started.");
sleep(1);
[self finish];
}
}
- (void)finish
{
NSLog(@"operationfinished.");
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
if (_isCancelled == YES)
{
NSLog(@"** OPERATION CANCELED **");
}
}
在我找到的示例中,我不明白为什么要使用performSelectorOnMainThread:。这将阻止我的操作同时运行
另外,当我注释掉那一行时,我的操作会同时运行。但是,
isCancelled
标志没有被修改,即使我已经调用了cancelAllOperations
查看。它是一个HTTP包装类,构建在NSOperation
的子类之上,似乎实现了这些功能。请注意,从2011年年中开始,开发人员建议不要在新项目中使用ASI。好的,据我所知,您有两个问题:
performSelectorOnMainThread:
段?那代码是做什么的NSOperationQueue
上调用cancelAllOperations
时,为什么没有修改\u isCancelled
标志NSOperation
子类被称为MyOperation
,只是为了便于解释。我会解释你的误解,然后给出一个正确的例子
1.同时运行NSO操作
大多数情况下,您会将NSOperation
s与NSOperationQueue
一起使用,从您的代码中,听起来您就是在这样做的。在这种情况下,您的MyOperation
将始终在后台线程上运行,而不管-(BOOL)concurrent
方法返回什么,因为NSOperationQueue
被明确设计为在后台运行操作
因此,通常不需要重写-[NSOperation start]
方法,因为默认情况下它只调用-main
方法。这是您应该覆盖的方法。默认的-start
方法已在适当的时间为您处理设置isExecuting
和isFinished
因此,如果希望NSOperation
在后台运行,只需重写-main
方法并将其置于NSOperationQueue
上即可
代码中的performSelectorOnMainThread:
将导致MyOperation
的每个实例始终在主线程上执行其任务。由于一次只能在线程上运行一段代码,这意味着没有其他MyOperation
s可以运行。NSOperation
和NSOperationQueue
的全部目的是在后台做一些事情
只有在更新用户界面时,才需要将内容强制到主线程上。如果在MyOperation
完成时需要更新UI,则应使用performSelectorOnMainThread:
。我将在下面的示例中演示如何做到这一点
2.取消操作
-[NSOperationQueue cancelAllOperations]
调用-[NSOperation cancel]
方法,这会导致对-[NSOperation isCancelled]
的后续调用返回是
然而,您已经做了两件事使其无效
@isCancelled
覆盖NSOperation的-isCancelled
方法。没有理由这样做<代码>NSOperation已以完全可接受的方式实现了-isCancelled
\u isCancelled
实例变量,以确定操作是否已取消NSOperation
保证如果操作已取消,[self isCancelled]
将返回YES
。它不能保证调用自定义setter方法,也不能保证自己的实例变量是最新的。您应该检查[自我取消]
// MyOperation.h
@interface MyOperation : NSOperation {
}
@end
以及实施:
// MyOperation.m
@implementation MyOperation
- (void)main {
if ([self isCancelled]) {
NSLog(@"** operation cancelled **");
}
// Do some work here
NSLog(@"Working... working....")
if ([self isCancelled]) {
NSLog(@"** operation cancelled **");
}
// Do any clean-up work here...
// If you need to update some UI when the operation is complete, do this:
[self performSelectorOnMainThread:@selector(updateButton) withObject:nil waitUntilDone:NO];
NSLog(@"Operation finished");
}
- (void)updateButton {
// Update the button here
}
@end
请注意,您不需要对isExecuting
、isCancelled
、或isFinished
执行任何操作。这些都是自动为您处理的。只需重写-main
方法即可。就这么简单
(注意:从技术上讲,这不是一个“并发的”NSOperation
,即-[MyOperation isConcurrent]
将返回上面实现的NO
。但是,它将在后台线程上运行。isConcurrent
方法确实应该命名为-willCreateOwnThread
,因为这是对该方法意图的更准确描述。)此博文:
解释为什么您可能需要:
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
在你的
start
方法中。我知道这是一个老问题,但我最近一直在研究这个问题,遇到了同样的例子,也有同样的疑问
如果您的所有工作都可以在main方法内同步运行,那么您不需要并发操作,也不需要重写start,只需完成工作并在完成后从main返回即可
但是,如果您的工作负载本质上是异步的,即加载NSURLConnection,那么您必须将start子类化。当start方法返回时,操作尚未完成。只有当您手动将KVO通知发送到isFinished和isExecuting标志时(例如,异步URL加载完成或失败),NSOperationQueue才会将其视为已完成
最后,当要启动的异步工作负载需要在主线程上侦听运行循环时,可能需要将start分派到主线程。正如作品本身一样