2014-01-21 15 views
0

我有問題,我有一些非常大的UIScrollView和噸圖像加載在用戶滾動。圖像存儲在設備上,但是我從服務器接收信息要顯示在UIScrollView的特定部分上。當用戶滾動一下時,我需要在新的位置顯示圖像,因爲我無法在啓動時使用圖像繪製整個UIScrollView。對於背景我有一個相對較小的圖像,我在整個視圖中移動。但問題是,在該背景之上,我應該繪製大量的UIImage對象(大約300-400),這些對象不是特別的bih,而是分層的(一個圖像位於其他頂層)。在繪圖時阻止滾動不是一種選擇。準備有很多圖層的背景線程的UIImage

現在我試圖決定哪一種方法會適合我最好的:

  1. 添加所需的所有圖像的UIView在後臺線程,然後只需添加到UIView的滾動型的主線程(希望不會需要很長時間)。這裏當滾動某處時,我需要計算並創建帶有對象的新UIView,並將其放置在現有和可能的位置,以便在用戶繼續沿某個方向滾動時刪除具有所有對象和圖層的第一個UIView。

  2. 將圖像中的所有圖層與CoreGraphics相結合,並將它們呈現爲已確定圖層的對象。通過這種方式,我可以從滾動視圖中移除特定對象(圖像)。當用戶滾動時,我只是創建新對象並將它們添加爲以完整對象的形式查看,並且可以在用戶滾動到足夠的位置時刪除對象,而不是刪除整個視圖。這裏的問題是在主線程中向UIScrollView添加多個對象,但是當它們結合時它們不會超過15-20個對象。

我最關心的是性能和線程。正如我所說我不能阻止主線程(或者說讓用戶不會注意的時候不能這樣做),並且不能將圖像合併到我的圖形部門,因爲它們有很多變化,這些變化是在運行時決定的。這就是爲什麼我正在考慮一種在後臺線程上準備數據的方法,並且只是在主線程上快速添加數據,而不是在主線程上準備和添加它(這會阻止UI)。

每一個幫助將大大appriciated!

問候,

hris.to

回答

0

看看使用CATiledLayer爲一個UIView背襯。它是爲此而設計的。

我有一個地圖在UIScrollView中有一個UIView,而UIView的大小是整個地圖的全部大小。 CATiledLayer處理何時繪製視圖的每個圖塊。

+0

請不要使用堆棧溢出通過鏈接來推廣你的網站;答案只應包括相關的代碼,而不是其他網站的鏈接。 – LittleBobbyTables

+0

@LittleBobbyTables感謝您的領導!我一定不會再這樣做。 –

0

好的,所以我在這裏寫,只是爲了讓你知道我如何解決我的問題。

主要問題是我在滾動時移動背景圖片(所以我沒有加載一個巨大的文件),同時這樣做是從服務器獲取信息並嘗試在相同的圖塊上繪圖,這會導致系統崩潰衆所周知崩潰:

CALayer was muted while enumerated 

我得靠performSelector法@Synchronized一起,但事實證明,這不是有效的,有時兩個線程(主UI線程和後臺線程)正試圖改變在屏幕上相同的瓷磚。所以基本上我所做的是改變背景提取和借鑑:

[self performSelectorOnBackgroundThread] 

使用混凝土後臺線程,而我存儲參考:每次我需要加載新的瓷磚

@property(nonatomic, strong) NSThread* backgroundThread; 

現在或者我需要移動背景,我在開始任何其他操作之前取消此線程(並確保它已取消)。也有與此線程和其他視圖視圖之間切換時,作爲我危在旦夕一個小問題,我需要設置超時:

[_backgroundThread cancel]; 

int currentAttempts = 0; 
while([_backgroundThread isExecuting]) 
{ 
    if(currentAttempts == MAX_ATTEMPTS_TO_CANCEL_THREAD) 
    { 
     //make sure we dont hang and force background 
     _backgroundThread = nil; 
     return; 
    } 

    [_backgroundThread cancel]; 
    currentAttempts++; 
} 

在我的「scrollViewDidScroll」不過,我沒有使用遞歸,因爲這會在較舊的設備(如iPhone 4)上滾動時產生輕微的UI塊,這是不可接受的。所以我基本上只是取消線程,並希望得到取消不夠快(這與幾十個測試似乎是工作):

- (void)scrollViewDidScroll:(UIScrollView*)scrollView 
{ 
    [_backgroundThread cancel]; 

    //move background around 
    [self moveBackground]; 
} 

這種方法的缺點是,你需要大量的檢查在你的後臺線程爲呼叫'取消'實際上不會取消任何東西。根據蘋果文檔,它只會改變您的線程的isCancelled狀態,您有責任使該線程以基本上與正常退出相同的方式退出(因此係統有機會在線程後清除):

if([_backgroundThread isCancelled]) 
{ 
    return; 
} 

問候,

hris.to