3

我有我的UIView子類中的UITextView logView(試過atomicnonatomic)和NSOperationQueue uploadQueue屬性。 我添加志願我NSOperationQueue酒店的operationsCount這樣的:崩潰在附加到NSOperationQueue操作的observeValueForKeyPathCount

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

觀察員功能如下:

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    if ([object isKindOfClass: [NSOperationQueue class]]) { 
     NSLog(@"Keypath is: %@ change dictionary is: %@", keyPath, change); 
     NSInteger testnew = [[change objectForKey: @"new"] integerValue]; 
     NSInteger testold = [[change objectForKey: @"old"] integerValue]; 
     if (testnew > testold) { 
      [[self logView] setText: [NSString stringWithFormat: @"Uploading %d files", testnew]]; 
      objc_setAssociatedObject([self logView], @"max_value_of_uploads", [change objectForKey: @"new"], OBJC_ASSOCIATION_COPY); 
     } else { 
      NSInteger value = [objc_getAssociatedObject([self logView], @"max_value_of_uploads") integerValue]; 
      [[self logView] setText: [NSString stringWithFormat: @"Uploaded %d of %d files", testnew, value]]; 
     } 
    } 
} 

uploadQueue填土工程這樣的:

... 
    NSDictionary *iter; 
     NSEnumerator *enumerator = [objects objectEnumerator]; 
     while (iter = [enumerator nextObject]) { 
      Uploader *op = [[Uploader alloc] initWithFileName: [iter objectForKey: @"fileName"] 
                  FileID: [[iter objectForKey: @"fileID"] integerValue] 
                 AndSessionID: [self sess]]; 
      //Uploader *op = [[Uploader alloc] init]; 
      [[self uploadQueue] addOperation: op]; 
    ... 

沒有if-else塊,一切正常工作:我已經得到有關queu操作數量的NSLog消息e,數字是好的,依此類推。 但與if-else塊,我得到的碰撞,它看起來像這樣:

bool _WebTryThreadLock(bool), 0x10617fb0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now... 
1 WebThreadLock 
2 -[UITextView setText:] 
3 -[SincViewController observeValueForKeyPath:ofObject:change:context:] 
4 NSKeyValueNotifyObserver 
5 NSKeyValueDidChange 
6 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] 
7 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:usingBlock:] 
8 ____NSOQDelayedFinishOperations_block_invoke_0 
9 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] 
10 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:usingBlock:] 
11 __NSOQDelayedFinishOperations 
12 _dispatch_after_timer_callback 
13 _dispatch_source_invoke 
14 _dispatch_queue_invoke 
15 _dispatch_worker_thread2 
16 _pthread_wqthread 
17 start_wqthread 

它崩潰的else塊。 此外,我看不到我的logView有任何更改。 感謝您的幫助和迴應。

更新:performSelectorOnMainThread當設置文本保存我。

+1

請參閱:http://stackoverflow.com/questions/1244243/nsoperation-observer-and-thread-error – magma

回答

4

更新您的用戶界面時,請確保您在主線程中。一個可能的解決方案如下:

dispatch_async(dispatch_get_main_queue(), ^{ 
    if (testnew > testold) { 
     [[self logView] setText: [NSString stringWithFormat: @"Uploading %d files", testnew]]; 
     objc_setAssociatedObject([self logView], @"max_value_of_uploads", [change objectForKey: @"new"], OBJC_ASSOCIATION_COPY); 
    } else { 
     NSInteger value = [objc_getAssociatedObject([self logView], @"max_value_of_uploads") integerValue]; 
     [[self logView] setText: [NSString stringWithFormat: @"Uploaded %d of %d files", testnew, value]]; 
    } 
}); 

注意,使用dispatch_asyncdispatch_sync取決於你想要實現,但在後一種情況下,你的風險死鎖,除非你檢查什麼線程你是

參見: NSOperation, observer and thread error 其中有人建議您的移動UI代碼到一個單獨的方法:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    [self performSelectorOnMainThread:@selector(dataLoadingFinished:) withObject:nil waitUntilDone:YES]; 
} 

..這是一個很好的備用路由。

1

我建議你在這裏使用委託模式。您似乎將非常先進的技術與一些寬鬆的代碼混合在一起,這可能會很快導致問題。例如,我認爲你不需要關聯對象。

您的錯誤發生是因爲您順便從後臺線程訪問UI。你應該把你的UI調用(setText :)包裝在performSelectorOnMainThread:withObject:waitUntilDone:或者一個塊中。

+0

這就是寫錯了,是的。 但我真的不使用觀察者函數在主線程以外的任何線程。 我認爲這個問題存在於KVO的內部機制中,也許它使用了額外的線程? 無論如何,當設置文本保存我時'performSelectorOnMainThread'。 – folex

+1

觀察者將在任何發生變化的線程中被調用。並且您正在使用NSOperationQueue,所以是的,它將在後臺。 –

+0

但我無法得到它。 NSOperation實例從隊列中移出後發生更改。 NSOperationQueue就是這樣,它在主線程中「生活」。我的意思是,在所謂的後臺線程中造成事件明顯發生,但是它自身的改變必須發生在主線程中。我錯在哪裏?謝謝。 – folex

相關問題