我已经放弃了NSOperation并设置了我的completionBlock,但即使操作完成,它似乎永远不会进入 . 这是我的代码:
目录控制器类设置NSOperation:
- (void)setupOperation {
...
ImportWordOperation *importWordOperation = [[ImportWordOperation alloc] initWithCatalog:words];
[importWordOperation setMainObjectContext:[app managedObjectContext]];
[importWordOperation setCompletionBlock:^{
[(ViewController *)[[app window] rootViewController] fetchResults];
}];
[[NSOperationQueue mainQueue] addOperation:importWordOperation];
[importWordOperation release];
...
}
如您所见,我正在设置完成块以在主线程上执行某个方法,在其他控制器中执行 .
然后,在 main
我的子类NSOperation类: ImportWordOperation.m
中,我启动了后台操作 . 我甚至覆盖 isFinished
iVar以便触发完成方法:
- (void)setFinished:(BOOL)_finished {
finished = _finished;
}
- (BOOL)isFinished {
return (self.isCancelled ? YES: finished);
}
- (void)addWords:(NSDictionary *)userInfo {
NSError *error = nil;
AppDelegate *app = [AppDelegate sharedInstance];
NSManagedObjectContext *localMOC = [userInfo valueForKey:@"localMOC"];
NSEntityDescription *ent = [NSEntityDescription entityForName:@"Word" inManagedObjectContext:localMOC];
for (NSDictionary *dictWord in [userInfo objectForKey:@"words"]) {
Word *wordN = [[Word alloc] initWithEntity:ent insertIntoManagedObjectContext:localMOC];
[wordN setValuesForKeysWithDictionary:dictWord];
[wordN release];
}
if (![[userInfo valueForKey:@"localMOC"] save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[localMOC reset];
[self setFinished:YES];
}
- (void)main {
finished = NO;
NSManagedObjectContext *localMOC = nil;
NSUInteger type = NSConfinementConcurrencyType;
localMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:type];
[localMOC setUndoManager:nil];
[localMOC setParentContext:[self mainObjectContext]];
if (![self isCancelled]) {
if ([self.words count] > 0) {
[self performSelectorInBackground:@selector(addWords:) withObject:@{@"words":self.words, @"localMOC":localMOC}];
}
}
}
如果我删除了isFinished访问器方法,那么在 ImportWordOperation
完成之前调用完成块 .
我已经阅读了我发现的使用自己的完成块的代码,但是那么NSOperation子类中的完成块有什么用呢?
任何想法或指向类似的解决情况将不胜感激 .
2 回答
你有点陷入并发和非并发
NSOperation
子类之间的奇怪空间 . 通常,当您实现main
时,您的操作是非并发的,并且isFinished
会在main
退出后立即更改为YES
.但是,您已经提供了自己的
isFinished
实现,并对其进行了编码,以便isFinished
在main
退出之前不会返回YES
. 这使得您的操作在许多方面开始像并发操作一样 - 至少包括手动发出KVO通知的需要 .您问题的快速解决方案是使用
(will|did)ChangeValueForKey:
调用实现setFinished:
. (我还更改了ivar名称以反映命名主流命名约定) . 下面是一个NSOperation
子类,我相信它可以准确地模拟您的操作的工作方式,以并发方式完成 .我不熟悉你的要求,所以也许你迫切需要,但你的操作似乎更适合使用
start
而不是main
的并发操作 . 我已经实现了一个似乎正常工作的小例子 .我在实现
NSOperation
的异步子类时遇到了这个错误 .Swift引用键路径的方式是使用
#keyPath
指令,所以我这样做(_executing
和_finished
是我的内部变量):不幸的是,上面的
#keyPath
表达式分别解析为"executing"
和"finished"
,我们需要为"isExecuting"
和"isFinished"
抛出KVO通知 . 这就是completionBlock
未被调用的原因 .解决方案是硬编码它们: