2011-05-20 40 views
3

當前的應用程序,我正在開發用於iPad涉及處理許多網絡請求,並堅持在覈心數據處理結果。最好的處理方法很多ASIHttpRequests和核心數據操作的iPad應用程序

該場景如下 - 應用程序需要爲網格視圖中顯示的對象下載圖像,該網格視圖可顯示總共30個對象。每個對象最多可以包含15個PNG圖像(也可以在網格中)。由於服務器的實現方式(意思是我沒有實現它並且不能輕易改變它),每個圖像都必須單獨請求,所以我需要爲每個對象提出15個請求,而不僅僅是1個請求來下載全部15張圖片。

對於每個對象,我目前使用ASINetworkQueue排隊15個圖像請求。一旦隊列完成,我創建對象的縮略圖快照,其圖像顯示在網格中,然後將所有的png文件保存到核心數據中。

我目前正在主線程上運行除ASI異步處理的網絡請求以外的所有內容,但由於請求太多,因此應用程序UI基本上都處於鎖定狀態,直到處理完所有請求並將結果保存到內核數據。

我遇到的一個解決方案是執行核心數據操作,並在單獨的線程中寫入或使用宏中央調度。另一種方法是隻下載可見對象的圖像,並在用戶向下滾動時下載剩下的圖像。

我正在尋找其他建議,以幫助保持主要的UI響應或更好的方式來構建網絡和核心數據操作。謝謝。

+0

@ nsx241您是否嘗試將圖像保存到磁盤並僅將文件名存儲在覈心數據中? – 2011-05-20 07:14:56

+0

圖像被保留,因爲我們希望它們也可以脫機使用。這些圖像實際上是根據客戶數據從第三方圖表引擎動態生成的,因此如果我們在線,我們需要向服務器詢問最新信息。 – nsx241 2011-05-20 18:28:16

+0

@ nsx241我的意思是:你將圖像存儲爲核心數據的blob還是將它們保存在磁盤上? – 2011-05-20 18:31:58

回答

0

爲了解決問題,1隊列應該足以滿足所有圖像請求。

您可能想要做的是保持對請求的引用,以便在不再需要對象時可以取消它們。

對於鎖定,有考慮與圖像的幾件事情:

  1. 它們會被壓縮,所以他們需要被UIImages之前充氣,即在CPU上很沉重。
  2. 如果您曾經想寫入文件系統,那麼這個進程就會被鎖定。在另一個隊列中執行以避免鎖定。
  3. 這是從來沒有的Blob存儲到CoreData,文件路徑存儲爲核心的數據字符串和只用使用3種不同的NSOperationQueue隊列

將讓您的應用更爲敏感從磁盤讀取是個好主意: 1 ASIHTTPRequests(不創建一個新的,使用帶有startAsynchronous默認) 1圖像寫入磁盤 1圖像從磁盤

5

首先取的,避免存儲大斑點的核心數據,保存縮略圖沒問題(雖然你應該優化你的模型),但你應該存儲完整的IM在「文檔」文件夾中重新構建它的年齡。

你一定要使用隊列,要麼NSOperationQueue或ASI網絡隊列。我在有多個依賴項的應用程序中做類似的事情。因此,對於每個30個對象,你需要有一個塊(或工作功能)時,15幅圖像下載被調用。理想情況下,您希望從主線程中完成這項工作。把所有這些要求放在一起,我會說你至少需要兩個隊列,一個用於網絡請求,另一個用於工作塊,你應該使用NSBlockOperations,這使得整個事情變得更容易。因此,代碼將是這樣的......

// Loop through the objects 
for (NSArray *objectParts in objectsToDownload) { 

    // Create our Object 
    Object *obj = [Object insertIntoManagedObjectContext:self.moc]; 

    // This is the block which will do the post processing for the object 
    NSBlockOperation *processBlock = [NSBlockOperation blockOperationWithBlock:^{ 

     // Do post processing here, be very careful with multi-threading CoreData 
     // it's likely you'll need some class to dispatch you MOCs which have all 
     // all the observers set up. 

     // We're gonna assume that all the sub-images have been stored in a instance 
     // variable: 
     [obj performPostProcessing]; 

    }]; 

    // Given the list of 15 images which form each object 
    for (NSURL *part in objectParts) { 

     // Create the ASI request for this part 
     ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:part]; 

     // Configure the request 
     [request setDelegate:self]; 
     [request setDidFailSelector:@selector(partRequestDidFail:)]; 
     [request setDidFinishSelector:@selector(partRequestDidFinish:)]; 

     // Store the object in the UserInfo dictionary 
     NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:obj, @"Object", nil]; 
     [request setUserInfo:userInfo]; 

     // Add it as a dependency 
     [processBlock addDependency:request]; 

     // Add it to our network queue 
     [networkQueue addOperation:request]; 
    } 

    // Add the processBlock to our worker queue 
    [workerQueue addOperation:processBlock]; 
} 

然後你還需要編寫委託方法,該didFinish一個會是這個樣子......

- (void)partRequestDidFinish:(ASIHTTPRequest *)request { 
    // Remember this is one the main thread, so any heavy lifting should be 
    // put inside a block operation, and queued, which will complicate the 
    // dependencies somewhat, but is possible. 

    // Get the result data 
    NSData *data = [request responseData]; 

    // Get the object that it belongs to from the user info dic 
    Object *obj = [[request userInfo] objectForKey:@"Object"]; 

    // Keep track of the partial data in the object 
    [obj storePartialDataForPostProcessing:data]; 
} 

而且所有這些都會進入你的類,它連接到你的服務器並創建你的對象,所以它不是視圖控制器或任何東西,只是一個常規的NSObject子類。它需要有兩個隊列,一個管理對象上下文(以及更可能返回另一個MOC爲您在線程使用的方法,是這樣的:

// Fends a MOC suitable for use in the NSBlockOperations 
- (NSManagedObjectContext *)moc { 
    // Get a blank managed object context 
    NSManagedObjectContext *aContext = [[UIApplication sharedApplication] managedObjectContext; 
[aContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; 
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
    [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:aContext]; 
    return aContext; 

}

- (void)mergeChangesFromMOC:(NSNotification *)aNotification { 
    @try { 
     [self.managedObjectContext mergeChangesFromContextDidSaveNotification:aNotification]; 
     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 
     [nc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:[aNotification object]];  
    } 
    @catch (NSException * e) { 
     NSLog(@"Stopping on exception: %@", [e description]); 
    } 
    @finally {} 
} 

你還需要以某種方式監控進度,重新排隊失敗的下載,取消和保存MOC到最後。重新排隊失敗的下載是非常棘手的。無論如何,希望有幫助。

因此,只是爲了澄清,在你的委託方法,你會存儲下載的圖像您的對象上的臨時實例變量。然後,當所有15個依賴關係完成時,您可以訪問該實例變量並完成您的工作。

+0

謝謝。這是我在下一個版本中看到的方法。基本上一個請求隊列和另一個隊列處理。儘管我沒有考慮過塊操作,但它們看起來非常適合我需要完成的任務。肯定會嘗試利用它們。 – nsx241 2011-06-15 06:48:28

+0

這是非常非常棒的。謝謝! – GordyD 2011-10-10 08:07:10

0

由於您將顯示圖像查看,你爲什麼不SDwebImage:

SDImageCache管理異步下載隊列,與圖像緩存存儲捆綁下載器,保持內存緩存和一個可選的磁盤緩存。磁盤緩存寫入操作是異步執行的,因此它不會爲UI添加不必要的延遲。

[ImageView的setImageWithURL:[NSURL URLWithString:@ 「http://www.domain.com/path/to/image.jpg」] placeholderImage:[UIImage的imageNamed:@ 「placeholder.png」]]

https://github.com/rs/SDWebImage

相關問題