POST JSON данные в существующий объект

17

Я извлекаю данные JSON из URL-адреса, который отформатирован следующим образом:

{"zoneresponse":
{"tasks":
 [{"datafield1":"datafor1", 
   "datafield2":"datafor2", 
   "datafield3":"datafor3",...
 }]
}}

У меня нет контроля над структурой, так как это из частного API.

Как вставить данные в выбранное поле данных существующего объекта?

Я пробовал это:

self.responseData = [NSMutableData data];

//testingURL is the api address to the specific object in tasks
NSURL *url = [NSURL URLWithString:testingURL];

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[[[params objectForKey:@"zoneresponse"] objectForKey:@"tasks"] setValue:@"HelloWorld" forKey:@"datafield1"];
//HAVE TRIED setObject: @"" objectForKey: @"" as well

//*****PARAMS IS EMPTY WHEN PRINTED IN NSLog WHICH IS PART OF THE ISSUE - SETTING VALUE DOES NOT WORK

NSError * error = nil;

NSLog(@"Params is %@", params);

NSData *requestdata = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error];

NSMutableURLRequest *request;
request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%d", [requestdata length]] forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:requestdata];

NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];


if(conn) {
    NSLog(@"Connection Successful, connection is: %@", conn);

} else {
    NSLog(@"Connection could not be made");
}

Соединение выполняется, но параметры словаря пусты при печати (значение setValue не отображается) и не вводит никаких данных в поле, которое я выбираю.

Я проверил эти ссылки, но ничего не объясняет, будет ли он вставляться в правильное поле и подразумевает, что он создаст новый объект, а не обновит существующий.

Как обновить данные на сервере db через json апи?

Как отправить данные json в Запрос Http с использованием NSURLRequest

Методы делегирования

//any time a piece of data is received we will append it to the responseData object
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.responseData appendData:data];

    NSError *jsonError;

    id responseDict =
    [NSJSONSerialization JSONObjectWithData:self.responseData
                                options:NSJSONReadingAllowFragments
                                  error:&jsonError];

    NSLog(@"Did Receive data %@", responseDict);
}

 //if there is some sort of error, you can print the error or put in some other handling here, possibly even try again but you will risk an infinite loop then unless you impose some sort of limit
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // Clear the activeDownload property to allow later attempts
    self.responseData = nil;

    NSLog(@"Did NOT receive data ");

}

//connection has finished, the requestData object should contain the entirety of the response at this point
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSError *jsonError;
    id responseDict =
    [NSJSONSerialization JSONObjectWithData:self.responseData
                                options:NSJSONReadingAllowFragments
                                  error:&jsonError];
    if(responseDict)
    {
        NSLog(@"%@", responseDict);
    }
    else
    {
        NSLog(@"%@", [jsonError description]);
    }

    //clear out our response buffer for future requests
    self.responseData = nil;
}

В первом методе здесь говорится, что данные были получены с помощью «Получены данные приема (null)», нет никакой ошибки при подключении, однако последний метод печатает сообщение об ошибке «Текст JSON не запускался с массивом или объектом, а опция разрешить фрагменты не установлены. ", что понятно, потому что нет данных или отправляемых объектов.

Как вставить данные в выбранное поле существующего объекта?

    
задан App Dev Guy 16.04.2015 в 10:28
источник
  • где и как вы начинаете соединение? Я имею в виду [conn start] –  Vivek Molkar 16.04.2015 в 11:29
  • @VivekMolkar У меня есть это внутри метода (IBAction), и я предполагаю, что он подключается автономно на основе моих методов возврата - (void) соединение: (NSURLConnection *) connection didReceiveData: (NSData *) data, - (void) connection : (NSURLConnection *) connection didFailWithError: (NSError *) error и - (void) connectionDidFinishLoading: (NSURLConnection *) connection –  App Dev Guy 16.04.2015 в 12:02
  • Нет, вы должны поместить строку кода [conn start], чтобы инициировать соединение. само по себе не инициировать. –  Vivek Molkar 16.04.2015 в 12:07
  • ваши методы делегатов, они попадают? –  Vivek Molkar 16.04.2015 в 12:09
  • Boom !! У меня нет вариантов. Все, что я думал, было неправильным. Извините, чувак не имеет ответа сейчас :( –  Vivek Molkar 16.04.2015 в 13:12
Показать остальные комментарии

2 ответа

13

Вы делаете это неправильно:

NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[[[params objectForKey:@"zoneresponse"] objectForKey:@"tasks"] setValue:@"HelloWorld" forKey:@"datafield1"];

Ваш params - пустой словарь, и объект [params objectForKey:@"zoneresponse"] не возвращается.

Попробуйте следующее:

NSMutableDictionary *params = [NSMutableDictionary new];
params[@"zoneresponse"] = @{@"tasks": @{@"datafield1": @"HelloWorld"}};

Это будет работать, но объект для ключа @"tasks" будет неизменным. Чтобы добавить другие объекты в словарь tasks , нам нужно сделать его изменчивым:

NSMutableDictionary *params = [NSMutableDictionary new];
NSMutableDictionary *tasks = [NSMutableDictionary new];
params[@"zoneresponse"] = @{@"tasks": tasks};
params[@"zoneresponse"][@"tasks"][@"datafield1"] = @"HelloWorld";

или

NSMutableDictionary *params = [NSMutableDictionary new];    
params[@"zoneresponse"] = @{@"tasks": [@{@"datafield1": @"HelloWorld"} mutableCopy]};

Затем вы можете добавить еще один объект в tasks :

params[@"zoneresponse"][@"tasks"][@"datafield2"] = @"HelloWorld2";
params[@"zoneresponse"][@"tasks"][@"datafield3"] = @"HelloWorld3";

Я думаю, что мой ответ принесет определенную ясность в операции со словарями для вас.

    
ответ дан Vlad Che 22.04.2015 в 11:47
  • Отличный ответ благодаря кучам для этого. Действительно помог разобраться. –  App Dev Guy 26.04.2015 в 16:48
2

Архитектурный контекст вашего подхода к отправке данных JSON в базу данных серверов:

Вы используете старый метод (начиная с 03 ') запроса HTTP POST, чтобы получить ваши прекрасные данные JSON в базу данных серверов. Он по-прежнему является функциональным, а не устаревшим и, в конечном итоге, приемлемым подходом. Обычно, как работает этот подход, вы настраиваете и запускаете NSURLRequest с NSURLConnection, ViewController или объект, который запускал запрос, как правило, реализует протокол NSURLConnection, поэтому у вас есть метод обратного вызова, который получает ответ, связанный с NSURLRequests, как вы это делали. Также доступны некоторые NSURLCaching и NSHTTPCookStorage, чтобы избежать избыточности и ускорить все это.

Существует новый способ (с 13 '):

Преемником NSURLConnections является NSURLSession. Поскольку ответ Владимира Кравченко фокусируется на формировании NSDictionary для отправки в качестве параметра, который показал, что вам нужно использовать NSMutableDictionary вместо статического NSDictionary, который нельзя редактировать после его инициализации. Я сосредоточусь на сетевом подходе, окружающем ваш вопрос, хотя для того, чтобы быть полезным.

/*
The advantage of this code is it doesn't require implementing a
protocol or multiple callbacks.
It's self contained, uses a more modern framework, less code
and can be just thrown in to the viewDidAppear

Basically - theres less faffing about while being a little easier to understand.
*/
NSError *requestError;
// session config
NSURLSessionConfiguration *configuration = 
[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = 
[NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
// setup request
NSURL *url = [NSURL URLWithString:testingURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:60.0];

[request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setHTTPMethod:@"POST"];
// setup request parameters, Vladimir Kravchenko's use of literals seems fine and I've taken his code
NSDictionary *params = @{@"zoneresponse" : @{@"tasks" : [@{@"datafield1" : @"HelloWorld"} mutableCopy]}};
params[@"zoneresponse"][@"tasks"][@"datafield2"] = @"HelloWorld2";
params[@"zoneresponse"][@"tasks"][@"datafield3"] = @"HelloWorld3";
// encode parameters
NSData *postData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&requestError];
[request setHTTPBody:postData];
// fire request and handle response
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:
    ^(NSData *data, NSURLResponse *response, NSError *error) 
{
    NSError *responseError;
    // parse response
    NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&responseError];
    // handle response data
    if (responseError){
        NSLog(@"Error %@", responseError)
    }else{
        if (responseDict){
            NSLog(@"Response %@", responseDict);
        }
    }
}];

[postDataTask resume];

Дополнительная литература

Всегда замечательный Мэтт Томпсон написал о переходе от NSURLConnection к NSURLSession здесь: objc .io

Здесь вы можете найти другие похожие вопросы переполнения стека: Переполнение стека

Если вы хотите создать сетевую библиотеку, которая упростит эти проблемы, попробуйте найти MattT Thompsons AFNetworking, который можно найти здесь: GitHub

Дальнейший анализ NSURLConnection по сравнению с NSURLSession можно найти здесь: Рэй Вендерлих

    
ответ дан Sean Dev 27.04.2015 в 12:46
  • Действительно тщательный ответ. Мне придется попытаться выполнить все завтрашнее, так как я в настоящее время от стола. Я смотрел на AFNetworking, однако для всех интенсивных целей он не соответствовал тому, что мне нужно в этом конкретном случае, поэтому задавал вопрос. Вопрос о стеке не затрагивает конкретного вопроса, но, тем не менее, дает некоторые хорошие соображения относительно соединения. Спасибо за ответ. Я обязательно буду пытаться реализовать завтра. –  App Dev Guy 27.04.2015 в 13:28