2013-08-12 5 views
2

NSOperationQueue가있는 테스트 응용 프로그램을 개발 중입니다. NSInvocationOperation을 만들고 해당 작업의 "isFinished"속성을 관찰하고 있습니다. 이상하게도 observeValueForKeyPath가 가끔씩 만 호출됩니다. 매번 호출 할 때 변경해야 할 사항을 이해할 수 없습니다. 도와주세요.observeValueForKeyPath가 호출되지 않습니다.

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    ........//initialization 

    queue = [NSOperationQueue new]; 
    operation=[NSInvocationOperation new]; 

    operation = [[NSInvocationOperation alloc]initWithTarget:self  selector:@selector(CreateOperationWithContext:) object:context]; 

    [operation addObserver:self forKeyPath:@"isFinished" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; 

    [queue addOperation:operation]; 

    ..... // launch the view controller 
} 

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([keyPath isEqualToString:@"isFinished"]) { 
     NSLog(@"came in"); 
     [operation removeObserver:self forKeyPath:@"isFinished"]; 
    } 
    else 
    { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 
+0

'CreateOperationWithContext'에서 호출 여부와 확인 방법을 확인하는 방법은 무엇입니까? – Wain

+0

알림을 보지 못한 경우 여전히 'isFinished' KVN을 보지 못했지만 작업이 성공적으로 생성되고 실행되고 완료되었는지 100 % 확신합니까? 예를 들어,'@selector (CreateOperationWithContext :)'를 해결할 수 없었던 경우, 조작은 최초로 생성되지 않습니다. 또는'CreateOperationWithContext :'가 완료되지 못했다면 (무한 루프 등), 연산은 완료되지 않을 것이다. 그럼에도 불구하고'isFinished' 키에 대한 옵저버를 추가하는 대신 작업을위한 completionBlock을 설정하는 것이 좋습니다. 더 깨끗하고 안정적입니다. – Rob

+0

안녕하세요 Rob 및 Vain, 답장을 보내 주셔서 감사합니다. CreateOperationWithContext : 함수는 매번 호출되고 성공적으로 실행됩니다. 함수에서 데이터베이스를 업데이트하고 매번 업데이트를 볼 수 있습니다. 관찰자 만이 통보를받지 않습니다. – user2122350

답변

1

다음 코드는 나를 위해 작동 : 여기

내가 작성한 코드입니다. iOS 단일보기 앱 템플릿에서 시작했습니다. 여기에 내가 가진 무엇 :

@implementation SOAppDelegate 
{ 
    NSOperationQueue* queue; 
    NSOperation* operation; 
} 

- (void)CreateOperationWithContext: (id)foo 
{ 
    NSLog(@"Op ran"); 
} 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    queue = [NSOperationQueue new]; 
    // operation = [NSInvocationOperation new]; // Commented this out because it's redundant with the next line 
    operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(CreateOperationWithContext:) object:[NSObject new]]; 
    [operation addObserver:self forKeyPath:@"isFinished" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; 
    [queue addOperation:operation]; 
    return YES; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([keyPath isEqualToString:@"isFinished"]) 
    { 
     NSLog(@"came in"); 
     [operation removeObserver:self forKeyPath:@"isFinished"]; 
    } 
    else 
    { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 

// ... rest of empty default app delegate methods here... 

@end 

을 콘솔에서, 나는 참조 : -CreateOperationWithContext:의 구현에 대한

2013-08-13 08:04:15.150 TestOpKVO[71373:20b] Op ran 
2013-08-13 08:04:21.903 TestOpKVO[71373:20b] came in 

그래서 어떤 문제를 일으키는. 즉, 예외를 throw하도록 작업을 변경하더라도 KVO 알림이 여전히 호출되는 것을 볼 수 있습니다.

나는이 아주 기본적인 예제에서 시작하여 한 번에 한 단계 씩 진행하여 실제 코드에 적용하고 각 단계에서 알림이 작동하는지 확인합니다.

몇 가지 팁 (아마 당신이보고있는 문제에 관련이 있지만, KVO를 사용하는 모범 사례)

첫째, 당신의 관찰과 KVO 컨텍스트를 사용합니다. 더 안전하고 결정 론적입니다. 자세한 내용은 answer I wrote over here을 참조하십시오.

둘째로, -observeValueForKeyPath: (또는 -addObserver:...)의 호출 내에서 -removeObserver:forKeyPath:을 통보중인 동일한 keyPath로 호출하지 마십시오. 이것은 KVO의 내부 관찰자 데이터 구조를 엉망으로 만들 가능성이 있으며, 너트를 몰아 낼 수있는 비 결정적 크래시를 유발할 수 있습니다. 자세한 내용은 answer I wrote over here을 참조하십시오.

+0

이 효과를 발휘하게됩니다. CreateOperationWithcontext는 데이터베이스 업데이트를 수행합니다. 기능을 줄이고 테스트를 시도합니다. 고맙습니다 – user2122350

관련 문제