2

私たちのアプリケーションはほとんどが C++ で書かれており、そのコアは複数のプラットフォーム (Win、Mac、Android、iOS) で共有される静的ライブラリです。

iOS のサポートを追加し、サーバーとのすべての HTTP get/post 通信を実行する libcurl を使用する一連の機能を備えています。

しかし、iOS では、NSURLSession を使用してこれらの呼び出しを実装しています。

私の質問は非常に単純です.NSURLSessionDataTaskにC++のcompletionHandlerを提供するコードはどのように見えますか?

おそらく私はこれについて間違った方法で考えていますが、それは私が質問をするために考えることができる最も明確です.

世界のサンプルコードを使用して、次のことを試しましたが、役に立ちませんでした。完了ハンドラ内の Objective-C++ コードが呼び出されることはありません。C++ コードに戻り、戻りません。

これは目的の 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());
4

2 に答える 2

4

私があなたの質問を理解したら、get(std::string)取得が完了したら「コールバック」したいと考えています。のインターフェイスを変更したい場合、1 つの方法は、パラメータとして agetを渡すことです ...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++ の newstd::promiseおよびstd::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 のブロック機能にもあまり詳しくないので、構文には注意してください。

于 2015-02-02T23:32:45.437 に答える