thi*_*ryb 50 iphone nsoperation nsoperationqueue performselector
我无法找到关于如何子类化为NSOperation并发以及支持取消的良好文档.我阅读了Apple文档,但我无法找到"官方"示例.
这是我的源代码:
@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 **");
}
}
Run Code Online (Sandbox Code Playgroud)
在我发现的例子中,我不明白为什么使用performSelectorOnMainThread:.它会阻止我的操作同时运行.
此外,当我注释掉该行时,我会同时运行我的操作.但是,isCancelled即使我已经调用,也不会修改该标志cancelAllOperations.
BJ *_*mer 110
好的,据我所知,你有两个问题:
您是否需要performSelectorOnMainThread:代码中的注释中显示的细分?那段代码做了什么?
为什么_isCancelled当你打电话标志不修改cancelAllOperations对NSOperationQueue包含此操作?
让我们按顺序处理这些问题.我将假设你的子类NSOperation被调用MyOperation,只是为了便于解释.我将解释你的误解,然后给出一个更正的例子.
大多数情况下,你会使用NSOperations NSOperationQueue,而在你的代码中,听起来就像你正在做的那样.在这种情况下,MyOperation无论-(BOOL)isConcurrent方法返回什么,您将始终在后台线程上运行,因为NSOperationQueues明确设计为在后台运行操作.
因此,您通常不需要覆盖该-[NSOperation start]方法,因为默认情况下它只是调用该-main方法.这是你应该重写的方法.默认-start方法已在适当的时间处理设置isExecuting并isFinished为您处理.
因此,如果您希望NSOperation在后台运行,只需覆盖该-main方法并将其放在NSOperationQueue.
将performSelectorOnMainThread:在您的代码会导致每个实例MyOperation的主线程上总是执行它的任务.由于一次只能在一个线程上运行一段代码,这意味着没有其他MyOperations可以运行.的全部目的NSOperation和NSOperationQueue是做事情的背景.
您想要强制进入主线程的唯一时间是您更新用户界面时.如果您需要在MyOperation完成时更新UI ,那就是您应该使用的时间performSelectorOnMainThread:.我将在下面的示例中说明如何执行此操作.
-[NSOperationQueue cancelAllOperations]调用该-[NSOperation cancel]方法,这会导致后续调用-[NSOperation isCancelled]返回YES.但是,你做了两件事使这个无效.
您正在使用@synthesize isCancelled覆盖NSOperation的-isCancelled方法.没有理由这样做.NSOperation已经-isCancelled以完全可以接受的方式实施.
您正在检查自己的_isCancelled实例变量以确定操作是否已被取消.NSOperation保证在操作被取消时[self isCancelled]返回YES.它并不能保证您定制的setter方法会被调用,也不是说你自己的实例变量是最新的.你应该检查[self isCancelled]
标题:
// MyOperation.h
@interface MyOperation : NSOperation {
}
@end
Run Code Online (Sandbox Code Playgroud)
并实施:
// 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
Run Code Online (Sandbox Code Playgroud)
请注意,你不需要用做任何事情isExecuting,isCancelled或isFinished.这些都是自动处理的.只需覆盖该-main方法即可.就这么简单.
(A注:从技术上讲,这不是一个"并行" NSOperation,在一定意义-[MyOperation isConcurrent]将返回NO如上实现.然而,它,就会被在后台线程上运行的.isConcurrent方法真的应该被命名-willCreateOwnThread,因为这是一个更准确的描述方法的意图.)
@BJHomer 的出色答案值得更新。
并发操作应该重写该start方法而不是main.
正如苹果文档中所述:
如果要创建并发操作,则至少需要重写以下方法和属性:
startasynchronousexecutingfinished正确的实现也需要重写cancel。使子类线程安全并获得正确的所需语义也相当棘手。
因此,我将一个完整且可工作的子类作为在 Code Review中用 Swift 实现的提案。欢迎提出意见和建议。
该类可以轻松用作自定义操作类的基类。
| 归档时间: |
|
| 查看次数: |
46208 次 |
| 最近记录: |