2014-06-12 30 views
0

我對iOS很新,一般在多線程環境中工作。我有一個comp sci背景,因此您可以想象,我知道沒有人實際使用信號量來管理iOS應用程序的線程,我感到沮喪。處理iOS開發中的異步化問題

我知道如何使用代表來提供回叫,我也能夠使用塊。這些工作適用於某些情況,例如請求可能不會立即可用的數據,但在看起來需要一系列依賴操作時遇到問題。

例如,我目前正在努力的問題涉及使用「Box」API。

我想:

  1. 有我主要的應用程序能夠撥打電話一箱管理器類,在這種情況下發送多個請求創建遠程文件夾
  2. 讓每個文件夾而不箱管理器創建其每次成功創建遠程目錄

的問題時回調的主類:

如果有多個請求來創建共享父目錄的文件夾,則只有一個會創建父目錄,其餘的將返回409錯誤。 API不允許你從/ home/photos/..這樣的路徑創建一個文件夾,你只需要提供一個名稱和它應該創建的父文件夾的ID。這個錯誤表明其中一個文件夾已經存在(父母)。

我可以看到解決這個問題的唯一方法是至少有第一個文件夾與給定的父母在其他人之前創建。我已經閱讀了很多其他線程,說如果你試圖讓一系列的操作同步,那麼你做錯了什麼,所以我的問題是我在哪裏想錯在這裏想這個?我應該如何思考這種情況,以便看到異步解決方案?

這裏是我使用的嘗試創建文件夾的方法:

//Folder Creation 
- (void) createFolderFromPath:(NSString *)path 
{ 
    NSArray *pathWithoutRoot = [path pathComponents]; 
    pathWithoutRoot = [pathWithoutRoot subarrayWithRange:NSMakeRange(1, [pathWithoutRoot count]-1)]; 
    [self createFolderFromPathComponents:pathWithoutRoot withParentId:BoxAPIFolderIDRoot]; 
} 

- (int) createFolderFromPathComponents:(NSArray *)pathComponents withParentId:(NSString  *)parentId 
{ 
    if ([pathComponents count] < 1) 
     return EXIT_SUCCESS; 

    NSString *parent = pathComponents[0]; 
    NSArray *remainder = [pathComponents subarrayWithRange:NSMakeRange(1, [pathComponents count]-1)]; 

    BoxFoldersRequestBuilder *folderBuilder = [[BoxFoldersRequestBuilder alloc]init]; 
    folderBuilder.name = parent; 
    folderBuilder.parentID = parentId; 

BoxFolderBlock success = ^(BoxFolder *folder) 
{ 
    NSDictionary *folderInfo = folder.rawResponseJSON; 
    [self.treeInfo setObject:folderInfo[@"id"] forKey:folderInfo[@"name"]]; 
    [self createFolderFromPathComponents:remainder withParentId:folderInfo[@"id"]]; 
    }; 
    BoxAPIJSONFailureBlock failure = ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSDictionary *JSONDictionary) 
    { 
     NSLog(@"Error creating file with dictionary %@",JSONDictionary); 
     NSLog(@"Error creating file with error %@",error); 
     NSLog(@"Error creating file with response %@",response); 
     //Returns a 409, If I could get the ID of the folder I colided with here that would pretty much solve things, 
     //but Box does not send that information 

    }; 

    [[BoxSDK sharedSDK].foldersManager createFolderWithRequestBuilder:folderBuilder success:success failure:failure]; 
    return EXIT_SUCCESS; 
} 
+1

同步和順序之間有區別。如果您有一系列需要按照特定順序完成的操作(例如在創建子項之前創建父文件夾),那麼就是這樣。您可以使用順序調度隊列,以便任務可以異步排隊,但是會按順序執行。您還可以分析您的任務以確定順序發生哪些需求(在文件之前創建父文件),哪些可以並行發生(創建文件)並將任務提交到相應類型的隊列 – Paulw11

+0

如果必須編寫代碼我每天寫信號量,鎖等,我會完全發瘋。 – gnasher729

回答

0

我有一個基本的計算機科學的背景,所以你可以在 想象我沮喪的是學習,沒有人真正使用信號來管理線程爲 iOS應用程序。

稱爲「Grand Central Dispatch」的技術爲您處理信號量。您使用更高級別的抽象(隊列,塊,組)而不是信號量。 GCD還處理使用塊的回調模式,與代理相比,線路要少得多。

您可以使用遞歸方法來檢查並可能在後臺線程上創建父文件夾。成功和失敗塊確保父文件夾在子文件夾之前創建。

//This method always returns immediately and uses blocks to inform the caller when finished. 
- (void)createFolder:(NSString *)path 
     sucessBlock:(void(^)(void))success 
     failureBlock:(void(^)(void))failure //Failure only happens due to network or service disruption 
{ 
    //Recursive method does not create root path. 
    NSString * rootPath; 
    if ([path isEqualToString:rootPath]) 
    { 
     success(); 
     return; 
    } 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
        , ^{ 
         //Insert code to get folder info here. 
         BOOL folderExists = YES; 

         //If folder already exists, send success block. You may want to do this on the main thread depending on your class design. 
         if (folderExists) 
         { 
          success(); 
         } 
         else 
         { 
          //Insert code to get parent folder path. 
          NSString * parentFolder; 

          //Now make a recursive method call on the parent folder. 
          [self createFolder:parentFolder 
            sucessBlock:^{ 
             //This recursive method call will use success block when parent folder tree is established or if it already existed 

             /* 
             * Insert actual folder creation code for the path parameter here 
             */ 
             BOOL succeeded = YES; 
             if (succeeded) 
             { 
              success(); 
             } 
             else 
             { 
              failure(); 
             } 
            } 
           failureBlock:^{ 
            failure(); 
           }]; 
         } 
        }); 
} 
0

重要的概念編號1是runloop。在主線程中,有一個循環連續運行(不使用CPU時間,並在後面),當事件發生時以及調用適當的方法來處理它時得到通知。這原則上是MacOS X和iOS應用程序的工作原理。 GCD具有將代碼塊分派到該運行循環後面的隊列的功能。因此,所有事件處理方法以及派發到運行循環的所有代碼塊都將被一個接一個地執行。

重要的概念編號2是無限數量的後臺線程。 GCD具有將代碼塊分派給任何後臺線程的功能。所有這些代碼塊並行運行並最終完成。現在顯然,每個這樣的塊都可以自由地將代碼塊分配給運行循環,作爲最後一個動作完成之前 - 這就是人們所做的。

你很少等待其中一個塊完成,所以你很少需要信號量。你永遠不會等待一個塊完成,因爲該塊在完成時只是將一些塊分派給運行循環。如果您需要等待兩個或更多的塊完成,則創建一個調度組,這將會 - 當派發到該組的所有塊完成時分派一個塊。