簡體   English   中英

在ipad應用程序中處理許多ASIHttpRequests和核心數據操作的最佳方法

[英]Best way to handle many ASIHttpRequests and core data operations in ipad app

我正在為iPad開發的當前應用程序涉及處理許多網絡請求並將處理后的結果保存在核心數據中。

方案如下 - 應用程序需要下載我在網格視圖中顯示的對象的圖像,這可以顯示總共30個對象。 每個對象最多可包含15個png圖像(也在網格中)。 由於服務器的實現方式(意味着我沒有實現它並且無法輕松更改),每個映像必須單獨請求,因此每個對象最多需要15個請求,而不是只需要下載1個請求15張圖片。

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

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

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

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

首先,避免在Core Data中存儲大blob,保存縮略圖很好(盡管你應該為它優化你的模型),但是你應該在Documents文件夾中重建后存儲完整的圖像。

您絕對應該使用隊列,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。 重新排隊失敗的下載非常棘手。 無論如何,希望有所幫助。

因此,只是為了澄清,在您的委托方法中,您將下載的圖像存儲在Object上的臨時實例變量中。 然后,當所有15個依賴項完成后,您可以訪問該實例變量並完成您的工作。

為了解決問題,1 Queue應該足以滿足所有圖像請求。

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

對於鎖定,圖像需要考慮以下幾點:

  1. 它們是壓縮的,所以它們需要在UIImages之前充氣,這在CPU上非常沉重。
  2. 如果您想要寫入文件系統,那么該進程是鎖定的。 在另一個隊列中執行此操作以避免鎖定。
  3. 將Blob存儲到CoreData中永遠不是一個好主意,將文件路徑存儲為Core Data中的字符串並使用隊列從磁盤獲取

只使用3個不同的NSOperationQueue將使您的應用程序響應更快:1用於ASIHTTPRequests(不要創建新的,使用默認的startAsynchronous)1用於將圖像寫入磁盤1以從磁盤獲取圖像

由於您將顯示要查看的圖像,為什么不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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM