Chuỗi nền bắt đầu iOS


117

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 lấy dữ liệu từ sqlite và hiển thị cho người dùng.

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 chuỗi 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 tìm nạp và xử lý một chút, tôi cần cập nhật giao diện người dùng. Nhưng vì (như một phương pháp hay), chúng ta không nên thực hiện cập nhật giao diện người dùng từ các luồng nền. Tôi gọi một bảo trì selectornhư vậy -

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

Nhưng ứng dụng của tôi gặp sự cố trong bước đầu tiên. tức là bắt đầu một luồng nền. Đây không phải là cách để bắt đầu chuỗi nền trong iOS?

CẬP NHẬT 1: Sau khi [self performSelectorInBackground....tôi nhận được stacktrace này, không có thông tin gì -

nhập mô tả hình ảnh ở đây

CẬP NHẬT 2: Tôi thậm chí đã thử bắt đầu một chuỗi nền như vậy - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];nhưng tôi vẫn nhận được stacktrace tương tự.

Để tôi làm rõ, khi tôi thực hiện thao tác này trên luồng chính, 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;
}

Bạn nhận được nhật ký lỗi / sự cố nào?
jtbandes

Xin vui lòng xem cập nhật của tôi ...
Srikar Appalaraju

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

vâng, docidsđang retain. Tôi đã đặt nó trong .hnhư@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju

Không đặt tiền tố các phương thức với get; điều đó chỉ nên như vậyresultSetFromDB:
bbum

Câu trả lời:


270

Nếu bạn sử dụng performSelectorInBackground:withObject:để tạo ra một luồng mới, thì bộ chọn được thực hiện sẽ chịu trách nhiệm thiết lập nhóm tự động phát lại của luồng mới, vòng lặp chạy và các chi tiết cấu hình khác - xem "Sử dụng NSObject để tạo ra một Chủ đề" trong Hướng dẫn Lập trình Luồng của Apple .

Tuy nhiên, có lẽ bạn sẽ tốt hơn khi sử dụng Grand Central Dispatch :

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

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


Được cập nhật với một lời khen cho Chris Nolet , người đã đề xuất một thay đổi giúp mã trên đơn giản hơn và cập nhật các ví dụ mã GCD mới nhất của Apple.


mát mẻ! không biết điều này. Điều này [NSThread detachNewThreadSelector:@selector....cũng áp dụng cho ?
Srikar Appalaraju

Đúng. Theo tài liệu của Apple, việc gọi performSelectorInBackground:withObject:"giống như khi bạn gọi detachNewThreadSelector:toTarget:withObject:phương thức NSThreadvới đối tượng hiện tại, bộ chọn và đối tượng tham số làm tham số."
Scott Forbes

Có sự khác biệt giữa (unsigned long)NULL0trong vấn đề này không?
Sti

4
@Sti từ apple Dev Docs : Lưu ý: Đối số thứ hai của hàm disp_get_global_queue được dành cho việc mở rộng trong tương lai. Hiện tại, bạn phải luôn chuyển 0 cho đối số này.
Jawad Al Shaikh

Sau đó, tôi có nên sử dụng PerformSelectorOnMainThread để cập nhật giao diện người dùng với kết quả hoạt động hay có cách nhất quán hơn để cập nhật giao diện người dùng với GCD?
Ilya Denisov

9

Thực sự thì điều đó khá dễ dàng với GCD. Một quy trình công việc điển hình sẽ 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ể xem tài liệu của Apple tại đây


4

Kích hoạ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ó bất cứ điều gì để làm với điều đó. Ngoài ra, hãy kiểm tra xem docidscó thứ gì bên trong không và nó có được giữ lại không.

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


Vui lòng sao chép dòng bạn đã sử dụng chạy trơn tru trên luồng chính.
Nicolas S

Tôi sử dụng này từ chủ đề chính & ít nhất nó chạm phương pháp mà thay vì đột ngột đâm -[self getResultSetFromDB:docids];
Srikar Appalaraju

bạn đã kích hoạt những gì tôi đã nói với bạn?
Nicolas S

Đặt một điểm ngắt trong dòng này: SpotMain * mirror = [[SpotMain cert] init]; và cho tôi biết nếu nó bị đánh và, nếu tehn, dòng nào bị lỗi. Vui lòng kích hoạt zombies để chúng tôi có thể nhận được nhật ký lỗi rõ ràng.
Nicolas S

vâng, tôi đã kích hoạt zombie. Tôi nhận được thông báo này - `2011/08/14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: tin nhắn được gửi đến phiên bản deallocated 0x2bff80 2011/08/14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Object 0x2c0cc0 của lớp __NSCFData autoreleased không có hồ bơi tại chỗ - chỉ rò rỉ . Also when I try to call this method from background thread I do not reach SpotMain * gương ... `, Nó bị treo ngay sau khi xâm nhập vào sợi nền ...
Srikar Appalaraju

2

Thư viện sqlite mặc định đi kèm với iOS không được biên dịch bằng cách sử dụng macro SQLITE_THREADSAFE trên. Đây có thể là một lý do tại sao mã của bạn bị treo.


2

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

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.