处理iOS开发中的异步

时间:2014-06-12 12:54:00

标签: ios objective-c multithreading asynchronous box-api

我对iOS很陌生,一般在多线程环境中工作。我有一个comp sci背景,所以你可以想象我在学习没有人真正使用信号量来管理iOS应用程序的线程时感到沮丧。

我理解如何使用委托来提供回调,我也能够使用块。这些对于某些事情很有用,比如请求可能无法立即获得的数据,但是当我看起来需要一系列相关操作时,我遇到了麻烦。

例如,我目前正在努力解决的问题涉及使用" Box" API。

我想:

  1. 让我的主应用程序能够调用Box管理器类,并在这种情况下发送多个请求来创建远程文件夹
  2. 创建每个文件夹,而Box管理员每次成功创建远程目录时都必须回调主类
  3. 问题:

    如果有多个请求要创建共享父目录的文件夹,那么只有一个创建父目录,其余的将返回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;
    }
    

2 个答案:

答案 0 :(得分:0)

  

我有一个comp sci背景,所以你可以想象我的沮丧   了解到没有人真正使用信号量来管理线程   iOS应用

这些技术被称为&#34; Grand Central Dispatch&#34;为你处理信号量。您使用更高级别的抽象(队列,块,组)而不是信号量。 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();
                                 }];
                       }
                   });
}

答案 1 :(得分:0)

重要概念1是runloop。在主线程上,有一个循环连续运行(不使用CPU时间,在你的背后),在事件发生时得到通知,并调用适当的方法来处理它。原则上,MacOS X和iOS应用程序的工作原理。 GCD具有将代码块分派到该运行循环后面的队列的功能。因此,所有事件处理方法以及调度到运行循环的所有代码块将一个接一个地执行。

重要概念2是无限数量的后台线程。 GCD具有将代码块分派给任何后台线程的功能。所有这些代码块并行运行并最终完成。现在很明显,这些块中的每一个都可以自由地将代码块分配给运行循环,作为它完成之前的最后一个动作 - 这就是人们的行为。

你很少等待其中一个块完成,所以你很少需要信号量。您永远不会等待一个块完成,因为该块只是在完成时将一些块调度到运行循环。如果您需要等待两个或更多块完成,您将创建一个调度组,它将猜测是什么 - 在调度到该组的所有块都完成后调度块。