ios - 如何将 "C++ completion handler"传递给 NSURLSessionDataTask 来处理它返回的数据?

标签 ios objective-c objective-c++ completionhandler

我们的应用程序主要是用C++编写的,其核心是多个平台(Win、Mac、Android、iOS)共享的静态库。

我们正在添加 iOS 支持,并拥有一系列使用 libcurl 的函数来执行与我们的服务器的所有 HTTP get/post 通信。

但对于 iOS,我们现在使用 NSURLSession 实现这些调用。

我的问题非常简单,为 NSURLSessionDataTask 提供 C++completionHandler 的代码是什么样的?

也许我的思考方式是错误的,但这是我能想到的最清楚的提问方式。

使用世界上的示例代码,我尝试了以下操作,但无济于事。完成处理程序中的 Objective-C++ 代码永远不会被调用。它返回到 C++ 代码并且永远不会返回。

这是 Objective-C++ 函数:

std::string get(std::string urlStr)
{
    NSURLSession *defaultSession = [NSURLSession sharedSession];

    NSURL * url = [NSURL URLWithString:[NSString stringWithUTF8String:urlStr.c_str()]];

    __block std::string returnVal;

    NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithURL:url
                                                         completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if(error == nil)
        {
            NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
            NSLog(@"Data = %@",text);

            returnVal = std::string([text UTF8String]);
        }

    }];

    [dataTask resume];

    return returnVal;
}

这就是我在 C++ 中调用该代码的方式:

    response = get(url);
    fprintf(stderr, "Data in C++: %s", response.c_str());

最佳答案

如果我理解你的问题,你希望 get(std::string) 在完成获取后“给你回电话”。如果您愿意更改 get 的接口(interface),那么一种方法是将 std::function 作为参数传递...

void get(std::string urlStr, std::function<void(std::string)> callback)
{
  ...
  NSURLSessionDataTask* dataTask = 
    [defaultSession 
      dataTaskWithURL:url 
      completionHandler:
        ^(NSData *data, NSURLResponse *response, NSError *error) {
          if(error == nil)
          {
             NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
             NSLog(@"Data = %@",text);

             // invoke the callback here...
             callback(std::string([text UTF8String]));
          }
        }];
  ...
}

这将像这样使用......

void callbackFunc(std::string data)
{
  ...
}

get("...", callbackFunc);

构建此结构的另一种方法是使用 C++ 的新 std::promisestd::future 类型...

std::future<std::string> get(std::string urlStr)
{
  ...
  __block std::promise<std::string> p{};

  NSURLSessionDataTask* dataTask = 
    [defaultSession 
      dataTaskWithURL:url 
      completionHandler:
        ^(NSData *data, NSURLResponse *response, NSError *error) {
          if(error == nil)
          {
             NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
             NSLog(@"Data = %@",text);

             // Set the result value here...
             p.set_value(std::string([text UTF8String]));
          }
        }
    ];
  ...
  return p.get_future();
}

然后可以像这样使用......

auto result = get("...");

// other processing here ...
...

auto result_value = result.get();

注意:我应该指出,我假设使用 c++11/14。如果您使用的是 c++03,那么您仍然可以通过使用 boost::function 或裸函数指针来使用第一种方法 - void(*)(std::string)。我也不太熟悉 OS X 的 block 功能,所以要小心我的语法。

关于ios - 如何将 "C++ completion handler"传递给 NSURLSessionDataTask 来处理它返回的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28287661/

相关文章:

iPhone iOS 是否有开源带注释的折线图示例?

iphone - 向模态视图 Controller 的工具栏添加标题的正确方法?

iphone - 尝试使用快速角检测器成功实验室时,Apple O型匹配链接器错误

ios - 在 UITextView 中的 attributeText 中使用 html 时删除控制字符(回车、格式化?等)

ios - 代理背后的 XCode Swift 包管理器错误

ios - NSString hasPrefix : vs hasSuffix: which is less expensive?

objective-c - 删除 objective-c 中的身份验证凭据

xcode - XCode-ml.hpp中的#include <map>:没有这样的文件或目录

objective-c - 如何将 cfdictionaryref 存储到 NSDictionary 中

c++ - 为什么这个来自Objective-C++的dynamic_cast调试成功但发布失败?