Возвращение данных из NSURLSession через POST с JSON

Поскольку NSURLConnection больше не поддерживается, мне нужно перейти к NSURLSession. У меня есть URL и некоторые данные, которые мне нужно ввести как JSON. Тогда результатом должно быть возвращение JSON. Я вижу что-то вроде этого:

NSError *error;

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:@"[JSON SERVER"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:60.0];

[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];

[request setHTTPMethod:@"POST"];
NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: @"TEST IOS", @"name",
                     @"IOS TYPE", @"typemap",
                     nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
[request setHTTPBody:postData];


NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

}];

[postDataTask resume];

Я это правильный подход?

Мои требования: 1. Преврати мои пары ключ-значение в JSON. 2. Передайте URL и JSON в функцию многократного использования. 3. Получить возвращенные данные JSON. 4. Разобрать возвращенные данные JSON.

2 ответа

Решение

Вы хотите, чтобы вызывающие в вашем методе предоставили обработчик завершения, который выполняет такие вещи, как обработка возвращаемых данных или обновление пользовательского интерфейса, чтобы указать завершение.

Как и в SDK, вы можете сделать то же самое, как описано ниже. Скажем, мы называем функцию makeRequest и требуется параметр, чтобы отправить как часть запроса. Объявите метод следующим образом:

- (void)makeRequest:(NSString *)param completion:(void (^)(NSDictionary *, NSError *))completion;

Реализуйте это так:

- (void)makeRequest:(NSString *)param
         completion:(void (^)(NSDictionary *, NSError *))completion {

    // your OP code goes here, e.g.
    NSError *error;
    NSURLSessionConfiguration *configuration = // and so on

    // use the param to form the request if it needs one, then...

    NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request 
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

        // here, we must abide by the interface of our completion handler.
        // we must call in EVERY code path, so the caller is never left waiting
        if (!error) {
            // convert the NSData response to a dictionary
            NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
            if (error) {
                // there was a parse error...maybe log it here, too
                completion(nil, error);
            } else {
                // success!
                completion(dictionary, nil);
            }
        } else {
            // error from the session...maybe log it here, too
            completion(nil, error);
        }
    }];
    [postDataTask resume];
}

Ваш код, который вызывает этот метод, будет выглядеть так:

// update the UI here to say "I'm busy making a request"
// call your function, which you've given a completion handler
[self makeRequest:@"someParam" completion:^(NSDictionary *someResult, NSError *error) {
    // here, update the UI to say "Not busy anymore"
    if (!error) {
        // update the model, which should cause views that depend on the model to update
        // e.g. [self.someUITableView reloadData];
    } else {
        // update UI to indicate error or take remedial action
    }
}];

Обратите внимание на пару вещей: (1) тип возвращаемого значения voidвызывающая сторона не ожидает ничего от этого метода и не присваивает его при вызове. "Возвращенные" данные предоставляются в качестве параметров обработчику завершения, который вызывается позже, после того, как запрос asnych завершен, (2) подпись обработчика завершения точно соответствует тому, что вызывающая сторона объявила в блоке завершения ^(NSDictionary *, NSError *)Это всего лишь предложение, типичное для сетевых запросов.

  1. Создать экземпляр NSURLSession а также NSMutableURLRequest объект:

    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setHTTPMethod:@"POST"];
    [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
    
  2. Превратите ваши пары ключ-значение в JSON:

    // choose the right type for your value.
    NSDictionary *postDict = @{@"key1": value1, @"key2": value2};
    NSData *postData = [NSJSONSerialization dataWithJSONObject:postDict options:0 error:nil];
    
  3. Создайте свой POST с помощью URL и JSON:

    [request setURL:[NSURL URLWithString:@"JSON SERVER"];
    [request setHTTPBody:postData];
    NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
    }];
    [postDataTask resume];
    
  4. Разобрать данные JSON, возвращенные в completionHandler выше:

    if (!error) {                        
        NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    } else {
        // error code here
    }
    

    responseDict это проанализированные данные. Например, если сервер возвращает

    {
        "message":"Your messsage",
        "data1":value1,
        "data2":value2
    }
    

    Вы можете легко получить значение для data1 используя

     [responseDict objectForKey:@"data1"];
    

Если вы хотите сделать еще один POST с другим URL или JSON, просто повторите последовательность шагов 2-4.

Надеюсь, мой ответ поможет.

Другие вопросы по тегам