2011-08-14 152 views
110

我在我的iOS設備中有一個小的sqlitedb。當用戶按下按鈕時,我從sqlite &中獲取數據將其顯示給用戶。iOS開始後臺線程

這個抓取部分我想在後臺線程中做(不阻塞UI主線程)。我這樣做,像這樣 -

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

的獲取&後處理的一點點,我需要更新UI。但是,由於(作爲一種好的做法),我們不應該從後臺線程執行UI更新。我在mainthread叫selector像這樣 -

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

但我的應用程序中的第一步崩潰。即開始後臺線程。這不是在iOS中啓動後臺線程的方法嗎?

更新1:[self performSelectorInBackground....後,我得到這個堆棧跟蹤,沒有任何信息含量都沒有 -

enter image description here

更新2:我甚至嘗試,啓動一個後臺線程像這樣 - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];但仍然我得到相同的堆棧跟蹤。

只是讓我澄清一下,當我在主線程都執行此操作運行流暢...

更新3這是我想從後臺

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids 
{ 
    SpotMain *mirror = [[SpotMain alloc] init]; 
    NSMutableArray *filteredDocids = toProceessDocids; 

    if(![gMediaBucket isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1]; 
    if(![gMediaType isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1]; 
    if(![gPlatform isEqualToString:@""]) 
     filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1]; 

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids]; 
    [filteredDocids release]; 
    [mirror release]; 

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO]; 
    return; 
} 
+0

什麼錯誤/崩潰日誌,你得到什麼? – jtbandes

+0

請參閱我的更新... –

+0

您能否在背景中顯示您所調用的方法?並確保對象'docids'保留。 – Rog

回答

264

如果使用performSelectorInBackground:withObject:產卵一個新的線程,然後進行選擇是負責建立新線程的自動釋放池,跑環和其他配置細節 - 見"Using NSObject to Spawn a Thread"蘋果線程編程指南英寸

你可能會更好使用Grand Central Dispatch,雖然:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    [self getResultSetFromDB:docids]; 
}); 

GCD是一個較新的技術,並在開銷內存方面和代碼行更有效。


更新帶帽子尖端Chris Nolet,誰建議的改變,使得上面的代碼更簡單,蘋果最新的GCD代碼示例保持向上。

+0

酷!不知道這個。這是否適用於'[NSThread detachNewThreadSelector:@selector ....'也? –

+0

是的。根據Apple文檔,調用'performSelectorInBackground:withObject:'「與將當前對象,選擇器和參數對象作爲參數調用'detachNewThreadSelector:toTarget:withObject:'NSThread方法'相同。 –

+0

在這件事情中,'(unsigned long)NULL'和'0'之間有區別嗎? – Sti

4

運行的方法啓用NSZombieEnabled以瞭解哪個對象正在釋放並被訪問。 然後檢查getResultSetFromDB:是否與此有關。同時檢查docids裏面是否有內容,以及是否保留。

這樣你就可以肯定沒有什麼不對。

+0

請複製您在主線程上使用的流暢運行的行。 –

+0

我使用這個從主線程&至少它擊中該方法,而不是突然崩潰 - '[self getResultSetFromDB:docids];' –

+0

你有沒有啓用我告訴你? –

2

iOS自帶的默認sqlite庫不是使用SQLITE_THREADSAFE宏編譯的。這可能是你的代碼崩潰的原因。

2

斯威夫特2.x的答案:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     self.getResultSetFromDB(docids) 
    } 
4

嗯,這是相當有GCD其實很容易。典型的工作流程是這樣的:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul); 
    dispatch_async(queue, ^{ 
     // Perform async operation 
     // Call your method/function here 
     // Example: 
     // NSString *result = [anObject calculateSomething]; 
       dispatch_sync(dispatch_get_main_queue(), ^{ 
        // Update UI 
        // Example: 
        // self.myLabel.text = result; 
       }); 
    }); 

更多關於GCD你可以看看到Apple's documentation here