我sublcassed一个的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
为了伊娃才会触发完成方法:
- (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子类的使用为完成块呢?
任何意见或指向一个类似的解决情况,将不胜感激。
你有种陷入并发和非并发之间一个奇怪的空间NSOperation
这里的子类。 通常,当您实现main
,你的操作是不同步,并isFinished
变化YES
,一旦main
出口。
但是,您提供自己实现isFinished
,而且编码它,以便isFinished
不会返回YES
后才main
已退出。 这使你的工作开始表现得像在许多方面并发操作 - 至少包括需要手动发出KVO通知。
快速解决您的问题,是落实setFinished:
使用(will|did)ChangeValueForKey:
来电。 (我也改变了伊娃的名字来命名反映当时的命名约定)。 下面是一个NSOperation
子类,我认为准确地模拟您的操作的运作,在并行的方式完成的条款。
@implementation TestOperation {
BOOL _isFinished;
}
- (void)setFinished:(BOOL)isFinished
{
[self willChangeValueForKey:@"isFinished"];
// Instance variable has the underscore prefix rather than the local
_isFinished = isFinished;
[self didChangeValueForKey:@"isFinished"];
}
- (BOOL)isFinished
{
return ([self isCancelled] ? YES : _isFinished);
}
- (void)main
{
NSLog(@"%@ is in main.",self);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
[self setFinished:YES];
});
}
@end
我不熟悉你的要求,因此,或许你有迫切的需求,但你的操作会显得更自然适合使用并发操作start
,而不是main
。 我实现了似乎是正常工作的一个小例子。
@implementation TestOperation {
BOOL _isFinished;
BOOL _isExecuting;
}
- (void)setFinished:(BOOL)isFinished
{
if (isFinished != _isFinished) {
[self willChangeValueForKey:@"isFinished"];
// Instance variable has the underscore prefix rather than the local
_isFinished = isFinished;
[self didChangeValueForKey:@"isFinished"];
}
}
- (BOOL)isFinished
{
return _isFinished || [self isCancelled];
}
- (void)cancel
{
[super cancel];
if ([self isExecuting]) {
[self setExecuting:NO];
[self setFinished:YES];
}
}
- (void)setExecuting:(BOOL)isExecuting {
if (isExecuting != _isExecuting) {
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = isExecuting;
[self didChangeValueForKey:@"isExecuting"];
}
}
- (BOOL)isExecuting
{
return _isExecuting;
}
- (void)start
{
NSLog(@"%@ is in start. isCancelled = %@", self, [self isCancelled] ? @"YES" : @"NO");
if (![self isCancelled]) {
[self setFinished:NO];
[self setExecuting:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
sleep(1);
[self setExecuting:NO];
[self setFinished:YES];
});
}
}
@end
而实现的异步子我遇到了这个错误NSOperation
。
引用关键路径的雨燕方法是使用#keyPath
指令,所以我这样做( _executing
和_finished
是我的内部变量):
self.willChangeValue(forKey: #keyPath(Operation.isExecuting))
self._executing = false
self.didChangeValue(forKey: #keyPath(Operation.isExecuting))
self.willChangeValue(forKey: #keyPath(Operation.isFinished))
self._finished = true
self.didChangeValue(forKey: #keyPath(Operation.isFinished))
不幸的是, #keyPath
上述决心的表达,以"executing"
和"finished"
,分别,我们需要抛出KVO通知"isExecuting"
和"isFinished"
。 这就是为什么completionBlock
是没有得到调用。
解决的办法是硬编码它们的方式:
self.willChangeValue(forKey: "isExecuting")
self._executing = false
self.didChangeValue(forKey: "isExecuting")
self.willChangeValue(forKey: "isFinished")
self._finished = true
self.didChangeValue(forKey: "isFinished")