2013-06-25 144 views
0

是否有可能performSelector:withObject:afterDelay:在子線程中不起作用?不適用於NSThread:performSelector:withObject:afterDelay:?

我還是新來的目標C和Xcode所以也許我錯過了一些明顯的東西......:/我真的很感謝一些幫助。

我想要做的就是顯示infolabel 3秒鐘,之後它將被隱藏。如果設置了新信息,3秒後隱藏標籤的線程將被取消。 (我不想通過舊線隱藏的新信息。)

源代碼:

- (void) setInfoLabel: (NSString*) labelText 
{ 
    // ... update label with text ... 

    infoLabel.hidden = NO; 

    if(appDelegate.infoThread != nil) [appDelegate.infoThread cancel]; // cancel last hide-thread, if it exists 

    NSThread *newThread = [[NSThread alloc] initWithTarget: self selector:@selector(setInfoLabelTimer) object: nil];// create new thread 
    appDelegate.infoThread = newThread; // save reference 
    [newThread start]; // start thread 


    [self performSelector:@selector(testY) withObject: nil afterDelay:1.0]; 

} 


-(void) setInfoLabelTimer 
{ 
    NSLog(@"setInfoLabelTimer"); 


    [self performSelector:@selector(testX) withObject: nil afterDelay:1.0]; 

    [self performSelector:@selector(hideInfoLabel) withObject: nil afterDelay:3.0]; 

    NSLog(@"Done?"); 
} 

-(void) testX 
{ 
NSLog(@"testX testX testX testX testX"); 

} 

-(void) testY 
{ 
    NSLog(@"testY testY testY testY testY"); 

} 

-(void) hideInfoLabel 
{ 
    NSLog(@"f hideInfoLabel"); 
    if(!([[NSThread currentThread] isCancelled])) { 
     AppDelegate *appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate]; 
     appDelegate.infoThread = nil; 
     appDelegate.infoLabel.hidden = YES; 
     [NSThread exit]; 
    } 
} 

控制檯產出:

  • setInfoLabelTimer
  • 完成?
  • 暴躁易怒暴躁易怒暴躁

正如你可以看到performSelector:withObject:afterDelay:不工作(--->「暴躁易怒暴躁易怒暴躁的」),但不是在子線程(它運行(--->「setInfoLabelTimer 「和」完成?「))

有沒有人知道爲什麼performSelector:withObject:afterDelay:不工作在子線程? (或者有什麼是我的錯?:()

最好的問候, 茶壺

+0

是的,它不工作。任何視圖相關的東西都必須是主要的。 –

+0

testx和testy方法在.h中定義? –

+0

你不應該搞亂後臺線程中的UIKit對象。 – bbum

回答

1

如果你想在線程上調用performSelector:withObject:afterDelay,這個線程必須有一個正在運行的RunLoop。查看Apple的Thread Programming Guide。 RunLoop和NSThread也是example

可以在setInfoLabelTimer添加以下代碼:

while (!self.isCancelled) 
{ 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode 
              beforeDate:[NSDate distantFuture]]; 
} 
+0

謝謝hrchen,你和Robs的帖子讓我明白這個問題! – Teapot

+0

示例鏈接中斷 – ademar111190

0

順便說一句,你可能要考慮與Grand Central Dispatch工作,GCD,來代替。如果你想要做的事在三秒鐘內,你可以:

double delayInSeconds = 3.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    // do stuff here, and because it's in the main queue, you can do UI stuff, too 
}); 

我也想請您看看Migrating Away From Threads併發編程指南


或者,您可以使用動畫塊,而不是使用GCD,您可以在其中指定3.0秒內想要發生的事情。您還可以用動畫過渡(在我的例子0.25秒爲單位),以便排控制的是多了幾分婉約:

[UIView animateWithDuration:0.25 
         delay:3.0 
        options:0 
       animations:^{ 
        // you can, for example, visually hide in gracefully over a 0.25 second span of time 

        infoLabel.alpha = 0.0; 
       } 
       completion:^(BOOL finished) { 
        // if you wanted to actually remove the view when the animation was done, you could do that here 

        [infoLabel removeFromSuperview]; 
       }]; 
+1

非常感謝,Rob!使用多線程真的不是最好的方法。:/ – Teapot

1

如果你正在運行一個「子」線程(ISN線程「T主線程),它可以在2的一個方式運行:

  1. 它運行一個單獨的方法,然後終止
  2. 它運行一個運行循環和從隊列中處理項目

如果線程運行在表單1中,您使用performSelector將項目放入隊列中(或至少嘗試)但它永遠不會被處理,線程將會終止。

如果你想在線程上使用performSelector,你需要做額外的工作。或者,您可以將該項目推送到運行循環運行的主線程上。

+0

謝謝,Wain! :) – Teapot

0

無需線程或GCD都做你想做的事情。

只需直接在主線程使用performSelector:withObject:afterDelay:,我們的動畫作爲@Rob指出,在主隊列,或NSTimer使用dispatch_after

+0

Hello bbum。沒錯,謝謝!它終於有效,我會在下次使用它之前閱讀更多有關多個線程的內容。帶了我一整天... – Teapot

相關問題