2011-10-21 14 views
9

İşlevimin yalnızca ana iş parçacığı üzerinde çalıştığından nasıl emin olabilirim? (UI öğelerini günceller)
Bunun gibi bir işlev 'kötü' olarak değerlendiriliyor mu?Fonksiyonun yalnızca ana iş parçasında çalıştığından emin olun.

-(void)updateSomethingOnMainThread_real { 
    // Do stuff on main thread 
} 

-(void)updateSomethingOnMainThread { 
    [self performSelectorOnMainThread:@selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO]; 
} 
+2

olası kopyası olasıdır [Dairesel yöntem çağrısına izin var mı?] (Http://stackoverflow.com/questions/7706329/is-circular-method-calling-allowed) – ughoavgfhw

cevap

8

Bu gayet:

-(void)updateSomethingOnMainThread { 
if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) 
    [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; 
else { 
    // Do stuff on main thread 
} 
} 

Başlangıçta ben böyle oldu, ikinci işlevi zorunda kalmamak için böyle yazdım. Ana iş parçacığı üzerinde kod yürütmek için GCD'yi de kullanabilirsiniz.

Bu SO gönderiyi teslim alın.

GCD to perform task in main thread

3

Alternatif olarak, Grand Central Dispatch API kullanabilirsiniz, ama çok kullanışlı değil: daha basit şekilde senkron çağrı gerekli değilse

-(void)updateSomethingOnMainThread { 
    void (^doStuff)(void) = ^{ 
     // stuff to be done 
    }; 

    // this check avoids possible deadlock resulting from 
    // calling dispatch_sync() on the same queue as current one 
    dispatch_queue_t mainQueue = dispatch_get_main_queue(); 
    if (mainQueue == dispatch_get_current_queue()) { 
     // execute code in place 
     doStuff(); 
    } else { 
     // dispatch doStuff() to main queue 
     dispatch_sync(mainQueue, doStuff); 
    } 
} 

aksi halde, sen dispatch_async() çağırabilirsiniz:

-(void)updateSomethingOnMainThread { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // do stuff 
    }); 
} 
+1

Bu işleve çağrı yaparsanız, bu koda dikkat edin. Ana iplik bağlayacak. – NJones

+0

Oops, doğru, üzgünüm. Bu yüzden, yöntem şu anki sıranın ana sıra olup olmadığını kontrol etmeli ve eğer değilse, gönder ve eğer varsa, bloğu yerinde çalıştır, değil mi? Bu kod GCD olmayan çözümden daha karmaşık hale getirecektir :) – ayoy

+0

Logan'ın cevabına dayanarak, sahip olduğunuz şeyin zaten doğru olduğunu düşünüyorum. Çek gerekli değil. – thelaws

5

Büyük bir başarı ile kullandığım bu basit #define'i yazdım:

01 o parametresiz olduğunu varsayarak
#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; return; } 

Bu şekilde, yöntem, ana iş parçacığı üzerinde yürütülmesine garanti etmek için ayoy metodu tabanlı OBEB uygulamasına alternatif olarak bu

- (void) updateTheThings { 
     ensureInMainThread(); 
     [self.dog setTailWag:YES]; 
     // etc... 
+0

Parametreleri nasıl ele alıyorsunuz? – Moshe

+2

@Moshe hangi parametreyi?Metodun herhangi bir parametreye ihtiyacı olmadığını düşünüyorum. :) – Kjuly

+0

Farklı bir iş parçacığına bir parametreyle bir yöntem iletmek istediysem ne olur? – Moshe

15

benziyor, ben GCD tabanlı Aşağıdaki kullanın (another answer of mine çekilen) benim kod işlevi:

void runOnMainThreadWithoutDeadlocking(void (^block)(void)) 
{ 
    if ([NSThread isMainThread]) 
    { 
     block(); 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

Daha sonra kodunda yerde bu yardımcı işlevi kullanabilirsiniz:

runOnMainThreadWithoutDeadlocking(^{ 
    // Do stuff that needs to be on the main thread 
}); 

Bu, hangi satırın bunu çağırdığı önemli değil, kapalı blokta gerçekleştirilen eylemlerin her zaman ana iş parçacığında çalışacağını garanti eder. Bu küçük kod ekler ve hangi kodun ana iş parçacığı üzerinde çalıştırılması gerektiği konusunda oldukça açık.

+0

+1 Brad, "deadlocking olmadan" adını kısaca açıklayabilir misiniz lütfen? Risk nedir ve hangi teknikler bundan kaçınamaz? 'NOU' 'deadUntilDone' ile' OUT 'deadouting değil' performSelectorOnMainThread 'de mi? –

+2

@Yar - Yukarıdaki bağlantıyı http://stackoverflow.com/a/5226271/19679 adresinde açıklarım. Ana kuyruğa eşzamanlı bir gönderim kullanılması ('waitperSelectorOnMainThread:' ile 'waitUntilDone' YES olarak ayarlanır), ana iş parçasında halihazırda çalışan bir şey çağrıldığında kilitlenecektir. Bu beni şaşırttı ve yukarıdaki yardımcı işlevini oluşturmamı sağladı. -performSelectorOnMainThread: 'waitUntilDone' YES olarak ayarlanmış olsa bile' 'bu problemi yoktur. Ana sıraya eşzamanlı olmayan gönderimler aynı kilitlenme sorununa sahip değil. –

İlgili konular