2013-07-11 72 views
0

我在後臺線程中運行數學計算。試圖在UITextView中實時發佈結果。但是,直到後臺線程完成後纔會顯示結果。爲什麼不?當後臺線程繁忙時UITextView不會滾動

我在後臺揭開序幕的方法,

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^() { 
    [self v2]; 
}); 

後臺線程方法的形式爲,

- (void) v2 { 
    NSString *result; 
    // ... loop a bunch of times generating lots of results 
    for (bunch of stuff to compute) { 
     // If using dispatch_async, nothing is displayed until this method finishes 
     // If dispatch_sync then it does display and update 
     result = [self computeNextValue]; 
     dispatch_async(dispatch_get_main_queue(), ^() { 
     textView.text = result; 
     }); 
    } // end computation 
} 

這實際上並沒有,直到我開始嘗試過太大的問題滾動視圖。痛苦地緩慢。所以我創建了一個NSTimer來定期滾動UITextView。但是,即使計時器彈出並且該方法運行以請求滾動,UITextView也不會滾動,直到後臺方法完成。

+0

您不在後臺執行。當你阻塞主線程時,UI只會凍結。 – jakenberg

回答

0

首先,確保你在block中使用weakSelf而不是self。

__weak MyClass weakSelf = self; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^() { 
    [weakSelf v2]; 
}); 

...

__weak MyClass weakSelf = self; 
dispatch_async(dispatch_get_main_queue(), ^() { 
    weakSelf.textView.text = result; 
}); 

但是,這不會導致延遲的更新。我非常懷疑隊列的優先級DISPATCH_QUEUE_PRIORITY_LOW。請改用DISPATCH_QUEUE_PRIORITY_DEFAULT。

+0

試了兩個。不用找了。 – David

0

我想我已經知道了,至少是憑經驗。

它看起來像在UITextView上設置文本或以編程方式啓動滾動設置在另一個線程中運行的動畫序列。似乎正在發生的事情是,設置UITextView文本的請求比UITextView設置動畫的能力快。當屬性再次發生變化時,它顯然會取消它在另一個線程上設置的早期動畫。當我繼續以變化的要求來淹沒它時,在'文本'的價值再次發生變化之前,它永遠無法完成它想要做的事情。

我的解決方案涉及多個步驟。

在我最初的方法中,我非常快速地將textView.text設置爲一些新值。我設置了一個定時器來定期請求UITextView滾動。 在我的修改中,我計算結果字符串的新值,但不要將其設置爲UITextView。相反,基於計時器定期在textview上設置文本。這允許文本視圖追上。

但是,我注意到這仍然不可靠。如果我碰巧在滾動時再次設置文本,會出現奇怪的效果,例如非常慢的滾動。似乎滾動動畫和文字的重複設置仍然造成問題。

所以解決這個問題,我創建了一個屬性來指示視圖是否滾動。將視圖控制器設置爲UITextField委託。當我請求視圖滾動時,我將該標誌設置爲指示其滾動。如果尚未滾動,則只更新內容和請求滾動。結束了很好的工作。無論我設置定時器的速度有多快,它都會適當地等待。

// ViewController.h 
@property BOOL isViewScrolling; 

// ViewController.m 
// initialize property in viewDidLoad 
- (void)viewDidLoad { 
    self.isViewScrolling = FALSE; 
    textView.delegate = self; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(scrollIt) userInfo:nil repeats:TRUE]; 
} 

- (void)scrollIt { 
    NSLog(@"scrollit thread=%d", [[NSThread currentThread]isMainThread]); 
    if (!self.isViewScrolling) { 
    textView.text = self.result; 
    NSRange range = NSMakeRange(textView.text.length - 1, 1); 
    self.isViewScrolling = TRUE; 
    [textView scrollRangeToVisible:range]; 
    } 
} 

// UITextView delegate 
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { 
    NSLog(@"Animation stopped"); 
    self.isViewScrolling = FALSE; 
} 
0

嘗試改變所述預定調度隊列串結束與背景。

__weak MyClass weakSelf = self; 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^() { 
     weakSelf.textView.text = result; 
    }); 

而且你應該添加一個UIActivityIndi​​cator,並開始在操作開始動畫,然後停止動畫的textview.text領域已更新後。

這是一個很好的功能,顯示用戶目前還正在做的過程

另外我想從NSThread遠離我讀過來自蘋果的幾個論壇和文檔是強調使用GCD和塊操作。

相關問題