iOS Arka Plan İş Parçacığını başlat


117

İOS cihazımda küçük bir sqlitedb var. Bir kullanıcı bir butona bastığında, verileri sqlite'dan alıp kullanıcıya gösteriyorum.

Bu getirme kısmını bir arka planda yapmak istiyorum (UI ana iş parçacığını engellememek için). Bunu böyle yapıyorum -

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

Getirme ve biraz işlemden sonra kullanıcı arayüzünü güncellemem gerekiyor. Ancak (iyi bir uygulama olarak) arka plan iş parçacıklarından UI güncellemesi yapmamalıyız. Bir ana selectorkonuya böyle sesleniyorum -

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

Ancak uygulamam ilk adımda çöküyor. yani bir arka plan iş parçacığı başlatmak. Bu, iOS'ta arka plan iş parçacıklarını başlatmanın bir yolu değil mi?

GÜNCELLEME 1:[self performSelectorInBackground.... Bu yığın izini aldıktan sonra , ne olursa olsun hiçbir bilgi yok -

görüntü açıklamasını buraya girin

GÜNCELLEME 2: Hatta böyle bir arka plan iş parçacığı başlatmayı denedim - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];ama yine de aynı yığın izini alıyorum.

Açıklığa kavuşturmak için, bu işlemi ana iş parçacığı üzerinde gerçekleştirdiğimde her şey sorunsuz çalışıyor ...

GÜNCELLEME 3 Bu arka planda çalıştırmaya çalıştığım yöntem

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

Hangi hata / kilitlenme günlüğünü alıyorsunuz?
jtbandes

Lütfen güncellemelerime bakın ...
Srikar Appalaraju

Lütfen aradığınız yöntemi arka planda gösterebilir misiniz? Ve nesnenin docidskorunduğundan emin olun .
Rog

evet, docidsöyledir retain. Ben bunu koyduk .holarak@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju

Yöntemleri get; bu sadece olmalıresultSetFromDB:
bbum

Yanıtlar:


270

Eğer kullanırsanız performSelectorInBackground:withObject:, yeni bir iş parçacığı spawn ardından gerçekleştirilen seçici yeni parçacığının sallanmasını havuzu, koşu döngü ve diğer yapılandırma ayrıntılarını kurma sorumludur - bkz "Spawn bir konuya NSObject kullanma" Apple'ın içinde Guide Programlama Threading .

Yine de, Grand Central Dispatch'i kullanmanız muhtemelen daha iyi olur :

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

GCD daha yeni bir teknolojidir ve bellek ek yükü ve kod satırları açısından daha verimlidir.


Yukarıdaki kodu daha basit hale getiren ve Apple'ın en son GCD kod örneklerine ayak uyduran bir değişiklik öneren Chris Nolet'e şapka ipucu ile güncellendi .


güzel! bunu bilmiyordum. Bu da geçerli [NSThread detachNewThreadSelector:@selector....mi?
Srikar Appalaraju

Evet. Apple belgelerine göre, performSelectorInBackground:withObject:" detachNewThreadSelector:toTarget:withObject:metodunu NSThreadparametre olarak geçerli nesne, seçici ve parametre nesnesiyle çağırmanızla aynıdır" çağrısı .
Scott Forbes

Bu konuda (unsigned long)NULLve 0arasında bir fark var mı ?
Sti

4
@Sti elma Dev gelen Dokümanlar : Not: dispatch_get_global_queue işlevine ikinci argüman gelecek genişleme için ayrılmıştır. Şimdilik, bu argüman için her zaman 0 geçmelisiniz.
Jawad Al Shaikh

Kullanıcı arayüzünü işlem sonuçlarıyla güncellemek için performSelectorOnMainThread kullanmalı mıyım yoksa GCD ile kullanıcı arayüzünü güncellemenin daha tutarlı bir yolu mu var?
Ilya Denisov

9

Aslında GCD ile bu oldukça kolay. Tipik bir iş akışı şu şekilde olabilir:

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 hakkında daha fazla bilgi için Apple'ın belgelerine buradan göz atabilirsiniz.


4

Hangi nesnenin serbest bırakıldığını ve ardından erişildiğini bilmek için NSZombieEnabled'ı etkinleştirin . Sonra getResultSetFromDB:bununla bir ilgisi olup olmadığını kontrol edin . Ayrıca docidsiçinde herhangi bir şey olup olmadığını ve saklanıp saklanmadığını kontrol edin .

Bu şekilde, yanlış bir şey olmadığından emin olabilirsiniz.


Lütfen kullandığınız satırı ana ileti dizisinde sorunsuzca kopyalayın.
Nicolas S

Bunu ana iş parçacığından kullanıyorum ve en azından aniden [self getResultSetFromDB:docids];
çökmek

sana söylediğimi etkinleştirdin mi
Nicolas S

Bu satıra bir kesme noktası koyun: SpotMain * mirror = [[SpotMain ayırma] init]; ve bana isabet ederse ve eğer tehn, hangi hat çöküyor söyle. Net bir hata günlüğü alabilmemiz için lütfen zombileri etkinleştirin.
Nicolas S

evet, zombileri etkinleştirdim. Bunu anlıyorum - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: ayrılan örneğe gönderilen ileti 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Yerinde havuz olmadan __NSCFData sınıfının 0x2c0cc0 nesnesi - sadece . Also when I try to call this method from background thread I do not reach SpotMain * aynası sızdırıyor ... ", Arka plan iş parçacığına girdikten hemen sonra çöküyor ...
Srikar Appalaraju

2

İOS ile birlikte gelen varsayılan sqlite kitaplığı, SQLITE_THREADSAFE makrosu kullanılarak derlenmez. Bu, kodunuzun çökmesinin bir nedeni olabilir.


2

Hızlı 2.x yanıtı:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.