Как получить данные для возврата из NSURLSessionDataTask

У меня есть контроллер представления регистрации, который обрабатывает весь пользовательский ввод и вызывает функцию в другом классе (wsClass), передавая ей эти данные как NSDictionary.

Вызывается функция в wsClass, устанавливается соединение, и данные возвращаются с сервера и становятся доступными в рамках сеанса.

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

Вот вызов в RegistrationViewController:

        wsClass *ws = [[wsClass alloc] init];
    NSDictionary *testDict = [[NSDictionary alloc] initWithObjectsAndKeys:username.text,@"username",email.text,@"email",password.text,@"password", nil];
    NSDictionary *respDict = [ws sendData:testDict];

Вот функция, вызываемая в wsClass.m:

- (NSDictionary *)sendData:(NSDictionary *)sendDict {
NSMutableString *sendStr = [[NSMutableString alloc] init];

[sendDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    [sendStr appendFormat:@"&%@=%@", key, obj];
}];

NSLog(@"sendStr is: %@",sendStr);
NSString *noteDataString = [NSString stringWithFormat:@"%@%@",REQUIRED,sendStr];

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlTest]];
request.HTTPBody = [noteDataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";

NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                    // The server answers with an error because it doesn't receive the params
                                                    // handle response
                                                    if(error == nil)
                                                    {
                                                        [getReqAlert dismissWithClickedButtonIndex:0 animated:YES];

                                                        NSError *e = nil;
                                                        jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableLeaves error: &e];

                                                        if (!jsonArray) {
                                                            NSLog(@"Error parsing JSON: %@", e);
                                                        } else {

                                                            NSLog(@"resp: %@ = %@",[jsonArray objectForKey:@"status"],[jsonArray objectForKey:@"msg"]);
                                                            NSLog(@"Dictionary count: %lu", jsonArray.count);
                                                        }
                                                    }
                                                }];

 [postDataTask resume];

return jsonArray;

}


person CrypTech Studios    schedule 01.01.2014    source источник


Ответы (4)


Публикация завершается асинхронно, поэтому ваш wsClass должен сообщить вызывающей стороне о завершении после завершения публикации. Хороший способ сделать это — дополнить метод sendData блоком кода, предоставленным вызывающей стороной, который должен быть запущен после завершения:

Измените sendData:, чтобы он выглядел так:

// it doesn't return anything, because all it does is launch the post
// but when the post is done, it invokes completion

- (void)sendData:(NSDictionary *)sendDict completion:(void (^)(NSDictionary *))completion {

    // the stuff you're already doing

        NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            // the stuff you're already doing
            // now tell the caller that you're done
            completion(jsonArray);
        }];
    }

Звонящий теперь выглядит так:

// change the UI to say "I'm busy doing the post"
[ws sendData:testDict completion:^(NSDictionary *responseDict) {
    NSLog(@"this runs later, after the post completes %@", responseDict);
    // change the UI to say "The post is done"
}];

Пара замечаний по этому поводу: (1) я не добавлял в блок параметр ошибки, возможно, вам следует это сделать. Проверьте это и вызовите блок либо с nil и ошибкой, либо с выводом json и error=nil. (2) Ваш код предполагает, что результат json анализируется как словарь. Убедитесь, что это всегда верно, прежде чем использовать это в коде. (3) Имена классов обычно начинаются с заглавных букв.

person danh    schedule 01.01.2014
comment
Это именно то, что я искал! Спасибо! ... Мне нужно будет дополнительно прочитать, чтобы полностью понять природу того, что здесь происходит с обработчиками завершения. Я довольно хорошо понимаю концепцию, просто не уверен в синтаксисе для будущего использования и ссылки... Еще раз спасибо - person CrypTech Studios; 01.01.2014
comment
Рад помочь. Это может быть полезно в качестве более общего ответа о синтаксисе блоков: к функциям"> stackoverflow.com/questions/18220645/. Кроме того, Apple предоставляет это общее руководство: разработчика. apple.com/library/ios/documentation/cocoa/Conceptual/ - person danh; 01.01.2014
comment
Будет ли хорошей практикой создание делегата и обратный вызов? - person Woodstock; 28.03.2015
comment
@Woodstock - да, хорошо в том смысле, что это тоже сработает. На мой взгляд, делегирование используется слишком часто, потому что блоки появились в языке относительно недавно. Я предпочитаю делегирование только в том случае, когда делегат может быть логически представлен как целый класс (даже лучше, когда в качестве делегата может выступать более одного класса). - person danh; 28.03.2015
comment
@danh Спасибо за ответ, очень интересно! - person Woodstock; 29.03.2015
comment
Ваш completion(jsonArray); помогает мне в моей проблеме. Спасибо. - person Mihir Oza; 12.05.2017

Вы можете использовать семафоры для ожидания до тех пор, пока блок не завершит выполнение, а затем вернет значение из функции

- (NSDictionary *)sendData:(NSDictionary *)sendDict {
NSMutableString *sendStr = [[NSMutableString alloc] init];

[sendDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[sendStr appendFormat:@"&%@=%@", key, obj];
}];

NSLog(@"sendStr is: %@",sendStr);
NSString *noteDataString = [NSString stringWithFormat:@"%@%@",REQUIRED,sendStr];

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlTest]];
request.HTTPBody = [noteDataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";


 let semaphore = dispatch_semaphore_create(0)

NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// The server answers with an error because it doesn't receive the params
// handle response
if(error == nil)
{
[getReqAlert dismissWithClickedButtonIndex:0 animated:YES];

NSError *e = nil;
jsonArray = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableLeaves error: &e];

if (!jsonArray) {
NSLog(@"Error parsing JSON: %@", e);
} else {

NSLog(@"resp: %@ = %@",[jsonArray objectForKey:@"status"],[jsonArray objectForKey:@"msg"]);
NSLog(@"Dictionary count: %lu", jsonArray.count);

     dispatch_semaphore_signal(semaphore)
}
}
}];

[postDataTask resume];
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return jsonArray;

}

person Harsh Thakur    schedule 21.09.2016

Это может сработать.

  1. Добавьте переменную интерфейса nsDictVariable для NSDict или что-то еще, что вы извлекаете в классе
  2. В SendData назначьте его: self.nsDictVariable = ....
person John Stack    schedule 27.09.2014

Попробуй это . Это будет хорошо работать.

-(void)loadDetails
{

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
[[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {


    _allVehicleLocationsArray = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    [self afterCompleteDoThis];


}] resume];


}

-(void)afterCompleteDoThis{

for (NSDictionary *vehicleDict in _allVehicleLocationsArray) {

    NSLog(@" PPP %@" , [vehicleDict valueForKey:@"vehicleType"]);

}
}
person user2068161    schedule 23.07.2016