草庐IT

ios - 具有依赖性的 AFHTTPSessionManager 和 NSOperation 队列(AFNetworking 2)

coder 2024-01-20 原文

在以前版本的 AFNetworking 上,我可以使用 AFHTTPRequestOperation 来创建多个请求,在它们之间创建依赖关系并很容易地将它们排入队列。示例(在 AFHTTPClient 子类中):

NSURLRequest *categoriesRequest = [self requestWithMethod:@"GET" path:@"categories" parameters:nil];
AFHTTPRequestOperation *categoriesOperation = [self HTTPRequestOperationWithRequest:categoriesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSArray *jsonCategories = responseObject;
    for (NSDictionary *jsonCategory in jsonCategories) {
        SPOCategory *category = [[SPOCategory alloc] initWithDictionary:jsonCategory];
        [self.categories addObject:category];
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // …
}];

NSURLRequest *incidencesRequest = [self requestWithMethod:@"GET" path:@"incidences" parameters:nil];
AFHTTPRequestOperation *incidencesOperation = [self HTTPRequestOperationWithRequest:incidencesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSArray *jsonIncidences = responseObject;
    for (NSDictionary *jsonIncidence in jsonIncidences) {
        SPOIncidence *incidence = [[SPOIncidence alloc] initWithDictionary:jsonIncidence];
        [self.incidences addObject:incidence];
    }

    completionBlock(self.incidences, self.categories, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // …
}];

[incidencesOperation addDependency:categoriesOperation];

[self enqueueBatchOfHTTPRequestOperations:@[categoriesOperation, incidencesOperation] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
    // Processing…
} completionBlock:^(NSArray *operations) {
    // Completed
}];

我知道我可以继续使用 AFHTTPRequestOperation 但是,我想知道在 AFHTTPSessionManager 的子类中是否有类似的方法来实现同样的事情>,使用 NSURLSession 作为支持库而不是 NSURLConnection

谢谢!

最佳答案

AFHTTPSessionManager 的连接工厂方法创建将由 NSURLSessionDataTask 对象表示的连接。

AFHTTPRequestOperation 不同,它们不是 NSOperation 子类,因此无法声明依赖关系。

可以想象像这样包装一个工厂方法

- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(NSDictionary *)parameters
                      success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                      failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;

进入返回 NSOperation 对象的辅助方法/函数。不过,这可能(将)变得很麻烦,而且看起来很奇怪。

如果你有足够的勇气考虑另一个第三方库,你可以按照下面的解释解决你的问题:

想法是用“Promise”表示异步操作的最终结果。将 Promise 视为结果的占位符,最终将由操作设置。所以,基本上你将一个工厂方法包装到一个工厂方法中,然后有效地产生一个具有这个签名的方法:

-(Promise*) fetchCategories;

-(Promise*) fetchCategoriesWithParameters:(NSDictionary*)parameters;

请注意,上述方法是异步 - 但它们没有完成处理程序。 Promise 将改为提供此功能。

最初,当 fetchCategories 返回时,promise 对象并不“包含”结果。

您通过分别“注册”完成处理程序 block 错误处理程序 block 分别获得(在稍后的某个时间)最终结果和错误> 像这样的 then 属性(伪代码):

  [self.fetchCategoriesWithParameters].then( 
      <success handler block>, 
      <failure handler block> ); 

更完整的代码片段:

Promise* categoriesPromise = [self fetchCategories];

categoriesPromise.then(^id(id result){
    self.categories = result;
    ... // (e.g, dispatch on main thread and reload table view)
    return nil;
}, ^id(NSError* error){
    NSLog(@"Error: %@", error);
    return nil;
});

注意:成功处理程序 block 的参数result 是操作的最终结果,也就是responseObject

现在,为了“链接”多个异步操作(包括处理程序),您可以这样做:

self.categoriesPromise = [self fetchCategories];

Promise* finalResult = self.categoriesPromise.then(^id(id result){
    NSArray *jsonCategories = result;
    for (NSDictionary *jsonCategory in jsonCategories) {
        SPOCategory *category = [[SPOCategory alloc] initWithDictionary:jsonCategory];
        [self.categories addObject:category];
    }
   return [self fetchIncidencesWithParams:result);
}, nil)
.then(^id(id result){
    NSArray *jsonIncidences = result;
    for (NSDictionary *jsonIncidence in jsonIncidences) {
        SPOIncidence *incidence = 
          [[SPOIncidence alloc] initWithDictionary:jsonIncidence];
        [self.incidences addObject:incidence];
    }
    return @[self.incidences, self.categories];
}, nil)
.then(^id(id result){
    NSArray* incidences = result[0];
    NSArray* categories = result[1];
    ...
    return nil;
}, nil /* error handler block */);

您创建并“解决”(即设置结果)一个 Promise,如下所示:

- (Promise*) fetchCategories {
    Promise* promise = [[Promise alloc] init];

    NSURLRequest *categoriesRequest = [self requestWithMethod:@"GET" path:@"categories" parameters:nil];
    AFHTTPRequestOperation *categoriesOperation = [self  HTTPRequestOperationWithRequest:categoriesRequest success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [promise fulfillWithResult:responseObject];
    }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [promise rejectWithReason:error];
    }];

    return promise;
}

免责声明:

有一些第三方 Objective-C 库以这种或类似的方式实现 Promise。我是 RXPromise 的作者根据 Promises/A+ 实现 promise 规范。

关于ios - 具有依赖性的 AFHTTPSessionManager 和 NSOperation 队列(AFNetworking 2),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19406777/

有关ios - 具有依赖性的 AFHTTPSessionManager 和 NSOperation 队列(AFNetworking 2)的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  7. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  8. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  9. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  10. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

随机推荐