iOS memulai Background Thread

117

Saya memiliki sqlitedb kecil di perangkat iOS saya. Ketika pengguna menekan tombol, saya mengambil data dari sqlite & menunjukkannya kepada pengguna.

Bagian pengambilan ini saya ingin melakukannya di thread latar belakang (untuk tidak memblokir thread utama UI). Saya melakukan ini seperti itu -

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

Setelah mengambil & sedikit pemrosesan, saya perlu memperbarui UI. Tetapi karena (sebagai praktik yang baik) kita tidak boleh melakukan pembaruan UI dari utas latar belakang. Saya menyebutnya selectordi mainthread seperti itu -

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

Tetapi Aplikasi saya macet pada langkah pertama. yaitu memulai thread latar belakang. Bukankah ini cara untuk memulai utas latar belakang di iOS?

UPDATE 1: Setelah [self performSelectorInBackground....saya mendapatkan stacktrace ini, tidak ada info apa pun -

masukkan deskripsi gambar di sini

PEMBARUAN 2: Saya bahkan mencoba, memulai utas latar belakang seperti itu - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];tetapi saya masih mendapatkan stacktrace yang sama.

Hanya untuk mengklarifikasi, ketika saya melakukan operasi ini di utas utama semuanya berjalan lancar ...

UPDATE 3 Ini adalah metode yang saya coba jalankan dari latar belakang

- (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;
}
Srikar Appalaraju
sumber
Log error / crash apa yang Anda dapatkan?
jtbandes
Silakan lihat pembaruan saya ...
Srikar Appalaraju
Bisakah Anda menunjukkan metode yang Anda panggil di latar belakang? Dan pastikan objek docidstersebut dipertahankan.
Rog
ya, docidsadalah retain. Saya telah memasukkannya .hsebagai@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju
Jangan awali metode dengan get; yang seharusnyaresultSetFromDB:
bbum

Jawaban:

270

Jika Anda menggunakan performSelectorInBackground:withObject:untuk menelurkan utas baru, maka pemilih yang dijalankan bertanggung jawab untuk menyiapkan kumpulan peluncuran otomatis utas baru, putaran proses, dan detail konfigurasi lainnya - lihat "Menggunakan NSObject untuk Menelurkan Utas" di Panduan Pemrograman Threading Apple .

Anda mungkin lebih baik menggunakan Grand Central Dispatch , meskipun:

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

GCD adalah teknologi yang lebih baru, dan lebih efisien dalam hal overhead memori dan baris kode.


Diperbarui dengan tip topi untuk Chris Nolet , yang menyarankan perubahan yang membuat kode di atas lebih sederhana dan mengikuti contoh kode GCD terbaru Apple.

Scott Forbes
sumber
keren! tidak tahu ini. Apakah ini [NSThread detachNewThreadSelector:@selector....juga berlaku untuk ?
Srikar Appalaraju
Iya. Menurut dokumen Apple, memanggil performSelectorInBackground:withObject:"sama seperti jika Anda memanggil detachNewThreadSelector:toTarget:withObject:metode NSThreaddengan objek saat ini, pemilih, dan objek parameter sebagai parameter".
Scott Forbes
Apakah ada perbedaan antara (unsigned long)NULLdan 0dalam hal ini?
Sti
4
@Sti dari apple Dev Docs : Catatan: Argumen kedua untuk fungsi dispatch_get_global_queue dicadangkan untuk perluasan di masa mendatang. Untuk saat ini, Anda harus selalu memberikan 0 untuk argumen ini.
Jawad Al Shaikh
Apakah saya harus menggunakan performSelectorOnMainThread untuk memperbarui UI dengan hasil operasi atau ada cara yang lebih konsisten untuk memperbarui UI dengan GCD?
Ilya Denisov
9

Sebenarnya cukup mudah dengan GCD. Alur kerja yang khas akan menjadi seperti ini:

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

Untuk informasi lebih lanjut tentang GCD, Anda dapat melihat dokumentasi Apple di sini

Pawan Ahire
sumber
4

Aktifkan NSZombieEnabled untuk mengetahui objek mana yang dirilis dan kemudian diakses. Kemudian periksa apakah getResultSetFromDB:ada hubungannya dengan itu. Juga periksa apakah docidsada sesuatu di dalamnya dan apakah itu disimpan.

Dengan cara ini Anda bisa yakin tidak ada yang salah.

Nicolas S
sumber
Harap salin baris yang Anda gunakan yang berjalan lancar di utas utama.
Nicolas S
Saya menggunakan ini dari utas utama & setidaknya itu mengenai metode itu alih-alih tiba-tiba menabrak -[self getResultSetFromDB:docids];
Srikar Appalaraju
sudahkah Anda mengaktifkan apa yang saya katakan?
Nicolas S
Letakkan breakpoint di baris ini: SpotMain * mirror = [[SpotMain alokasi] init]; dan beri tahu saya jika terkena dan, jika tidak, baris mana yang rusak. Harap aktifkan zombie agar kami bisa mendapatkan log kesalahan yang jelas.
Nicolas S
ya, saya telah mengaktifkan zombie. Saya mendapatkan ini - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: pesan dikirim ke instans deallocated 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Objek 0x2c0cc0 dari kelas __NSCFData diluncurkan secara otomatis tanpa pool di tempatnya - hanya membocorkan . Also when I try to call this method from background thread I do not reach cermin SpotMain * ... `, Ia crash segera setelah memasuki thread latar belakang ...
Srikar Appalaraju
2

Pustaka sqlite default yang disertakan dengan iOS tidak dikompilasi menggunakan makro SQLITE_THREADSAFE. Ini bisa menjadi alasan mengapa kode Anda mogok.

Mugunth
sumber
2

Jawaban Swift 2.x:

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