2011-08-14 32 views
110

Tôi có một sqlitedb nhỏ trong thiết bị iOS của mình. Khi người dùng nhấn một nút, tôi tìm nạp dữ liệu từ sqlite & hiển thị nó cho người dùng.iOS bắt đầu Chủ đề nền

Phần tìm nạp này tôi muốn thực hiện trong một chuỗi nền (để không chặn luồng chính của giao diện người dùng). Tôi làm điều này như vậy -

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

Sau khi lấy & một chút xử lý, tôi cần phải cập nhật giao diện người dùng. Nhưng vì (như là một thực hành tốt), chúng ta không nên thực hiện cập nhật UI từ các chủ đề nền. Tôi gọi một selector trên mainthread như vậy -

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

Nhưng App của tôi bị treo trong bước đầu tiên. tức là bắt đầu một chuỗi nền. Đây có phải là cách để bắt đầu chuỗi nền trong iOS không?

UPDATE 1: Sau [self performSelectorInBackground.... tôi nhận được stacktrace này, không có thông tin gì vậy bao giờ -

enter image description here

UPDATE 2: Tôi thậm chí đã cố gắng, bắt đầu một sợi nền như vậy - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids]; nhưng Tôi vẫn nhận được cùng một stacktrace.

Chỉ cần để tôi làm rõ, khi tôi thực hiện thao tác này trên chính chủ đề tất cả mọi thứ chạy trơn tru ...

CẬP NHẬT 3 Đây là phương pháp tôi đang cố gắng để chạy từ nền

- (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

gì lỗi/vụ tai nạn log nào bạn nhận được? – jtbandes

+0

Vui lòng xem nội dung cập nhật của tôi ... –

+0

Bạn có thể vui lòng hiển thị phương pháp bạn đang gọi trong nền không? Và đảm bảo đối tượng 'docids' được giữ lại. – Rog

Trả lời

264

Nếu bạn sử dụng performSelectorInBackground:withObject: để đẻ trứng một chủ đề mới, sau đó chọn biểu diễn chịu trách nhiệm cho việc thiết lập các chủ đề mới của hồ bơi autorelease, vòng lặp chạy và chi tiết cấu hình khác - xem "Using NSObject to Spawn a Thread" trong Threading Programming Guide của Apple.

Bạn có thể muốn được tốt hơn bằng cách sử dụng Grand Central Dispatch, mặc dù:

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

GCD là một công nghệ mới hơn, và hiệu quả hơn về bộ nhớ overhead và dòng mã.


Cập nhật với một mẹo mũ để Chris Nolet, người đã đề nghị một sự thay đổi đó làm cho các mã trên đơn giản hơn và giữ lên với các ví dụ mã mới nhất GCD của Apple.

+0

tuyệt vời! không biết điều này. Điều này có áp dụng cho '[NSThread detachNewThreadSelector: @selector ....' không? –

+0

Có. Mỗi tài liệu của Apple, gọi 'performSelectorInBackground: withObject:' "giống như khi bạn gọi phương thức' detachNewThreadSelector: toTarget: withObject: 'của' NSThread' với đối tượng hiện tại, bộ chọn và đối tượng tham số làm tham số. " –

+0

Có sự khác nhau giữa '(unsigned long) NULL' và' 0' trong vấn đề này không? – Sti

4

Bật NSZombieEnabled để biết đối tượng nào đang được phát hành và sau đó được truy cập. Sau đó kiểm tra xem getResultSetFromDB: có liên quan gì không. Ngoài ra, hãy kiểm tra xem docids có bất kỳ thứ gì bên trong và nếu nó đang được giữ lại.

Bằng cách này bạn có thể chắc chắn không có gì sai.

+0

Vui lòng sao chép dòng bạn đã sử dụng để chạy trơn tru trên chuỗi chính. –

+0

Tôi sử dụng điều này từ chủ đề chính và ít nhất nó chạm vào phương pháp đó thay vì đột ngột bị rơi - '[self getResultSetFromDB: docids];' –

+0

bạn đã bật những gì tôi đã nói với bạn chưa? –

2

Thư viện sqlite mặc định đi kèm với iOS không được biên dịch bằng macro SQLITE_THREADSAFE. Đây có thể là lý do khiến mã của bạn gặp sự cố.

2

Swift 2.x câu trả lời:

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

Vâng đó là khá dễ dàng thực sự với GCD. Một công việc điển hình sẽ là một cái gì đó như thế này:

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; 
       }); 
    }); 

Để biết thêm về GCD bạn có thể có một cái nhìn vào Apple's documentation here

Các vấn đề liên quan