Как вернуть данные, полученные из веб-сервиса в объективе (iPhone)? - PullRequest
5 голосов
/ 14 января 2012

Это может быть глупый вопрос. Извините, если это так.

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

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

вот мой код, который отлично работает:

- (NSData *) dataForMethod:(NSString *)webMethod withPostString:(NSString *)postString
{
    NSURL *url = [NSURL URLWithString:[SigameWebServiceAddress stringByAppendingFormat:@"%@%@", @"/", webMethod]];
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
    NSString *msgLength = [NSString stringWithFormat:@"%d", [postString length]];

    [req addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [req addValue:msgLength forHTTPHeaderField:@"Content-Length"];
    [req setHTTPMethod:@"POST"];
    [req setHTTPBody: [postString dataUsingEncoding:NSUTF8StringEncoding]];

    conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
    if (conn) 
    {
        webData = [NSMutableData data];
    }   

    // I WOULD LIKE TO RETURN WEBDATA TO THE CALLER HERE, BUT WEBDATA IS EMPTY NOW, THE  
    //connectionDidFinishLoading ONLY GETS CALLED WITH THE DATA I WANT AFTER THE COMPILER
    //IS DONE EXECUTING MY METHOD.
}

-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) response 
{
    [webData setLength: 0];
}

-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data 
{
    [webData appendData:data];
}

-(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error 
{
    NSLog(@"FATAL ERROR");
}

-(void) connectionDidFinishLoading:(NSURLConnection *) connection 
{
    NSLog(@"DONE. Received Bytes: %d", [webData length]);

    NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];

    //---shows the XML---
    NSLog(@"%@", theXML);  //NOW, THIS IS THE DATA I WANT. BUT HOW CAN I RETURN THIS TO 
                           //THE CALLER. I MEAN, THE CALLER THAT CALLED MY METHOD 
                           //+ (NSData *) dataForMethod: withPostString:
}

Любая помощь здесь приветствуется! Спасибо

Ответы [ 6 ]

11 голосов
/ 14 января 2012

Есть действительно два способа сделать это.

  1. Создание делегата интерфейса
  2. Использовать блоки

Я бы настоятельно рекомендовал не использовать синхронные методы - если только вы не / не создали вокруг них собственную асинхронную среду (т. Е. Вы вручную запускаете другой поток и выполняете свой синхронный запрос в этом потоке). В конечном итоге вы поймете, что запросы должны быть асинхронными, и вам придется заново обрабатывать все так, как они есть.

Чтобы дать краткий обзор двух вариантов, которые я дал:

1. Создайте делегат интерфейс

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

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

@protocol RequestClassDelegate <NSObject>

- (void)requestCompleted:(ResponseClass *)data;
- (void)requestError:(NSError *)error;

@end

Класс, который делает запрос, может выглядеть примерно так:

@interface RequestClass : NSObject

- (void)makeRequest:(id<RequestClassDelegate>)delegate;

@end

И реализация класса запроса может содержать некоторые из следующего, в дополнение к вашей логике соединения:

@implementation RequestClass
{
    __weak id<RequestClassDelegate> _delegate;
}

// Connection Logic, etc.

- (void)makeRequest:(id<RequestClassDelegate>)delegate
{
    _delegate = delegate;
    // Initiate the request...
}

-(void) connectionDidFinishLoading:(NSURLConnection *) connection 
{
    NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];

    // Processing, etc.

    // Here we'll call the delegate with the result:
    [_delegate requestCompleted:theResult];
}

@end

2. Использовать блоки

Это решение во многом совпадает с первым решением, но, на мой взгляд, более элегантно. Здесь мы изменим RequestClass на использование блоков вместо делегата:

typedef void (^requestCompletedBlock)(id);
typedef void (^requestErrorBlock)(NSError *);
@interface RequestClass : NSObject

@property (nonatomic, copy) requestCompletedBlock completed;
@property (nonatomic, copy) requestErrorBlock errored;

- (void)makeRequest:(requestCompletedBlock)completed error:(requestErrorBlock)error;

@end

И реализация этого может выглядеть примерно так:

@implementation RequestClass

@synthesize completed = _completed;
@synthesize errored = _errored;

// Connection Logic, etc.

- (void)makeRequest:(requestCompletedBlock)completed error:(requestErrorBlock)error
{
    self.completed = completed;
    self.errored = error;
    // Initiate the request...
}

-(void) connectionDidFinishLoading:(NSURLConnection *) connection 
{
    NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];

    // Processing, etc.

    // Here we'll call the delegate with the result:
    self.completed(theResult);
}

@end
2 голосов
/ 23 сентября 2013

Ответ Стива великолепен, и я могу только предложить способ использования блоков. На самом деле, поскольку я новичок в Objective-C, я реализовал подход, описанный Стивом. Работает отлично.

Пост для более подробной информации и моей собственной точки зрения вы можете найти здесь: http://kerkermeister.net/how-to-build-an-cocos2d-ios-app-communicating-with-a-restful-api-the-sequence/

В Посте содержатся все крошечные шаги, которые необходимо выполнить, чтобы получить подход к решению Стив с работающими блоками Это включает: - обновляемое представление, которое будет отображать информацию при ее асинхронном получении из Web API. - контроллер, вызывающий HTTP-запрос к веб-API - фактический класс HttpRequest, который использует стандарт iOS для NSURLConnections - класс модели, который использует блоки в качестве обратных вызовов для обновления своих данных

2 голосов
/ 14 января 2012

Звучит так, будто вы пытаетесь использовать возврат данных синхронно из вашего метода, но вы используете асинхронный метод (использующий NSURLConnection и предположительно вызывающий его метод запуска), чтобы начать извлечение данных. Если вы действительно хотите, чтобы ваш метод возвращал свой результат синхронно, читайте дальше. Как говорит @Steve в другом ответе, вы также можете пересмотреть свой дизайн интерфейса и вместо этого реализовать его, используя асинхронный подход, и использовать его рекомендации для делегированного или блочного интерфейса.

Если вы хотите вернуть данные синхронно из вашего метода, используйте синхронный запрос. Поэтому измените эту часть своего кода:

conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
[conn start]; // I presume you have this somewhere
if (conn) 
{
    webData = [NSMutableData data];
} 

с чем-то вроде этого:

 NSURLResponse *response = nil;
 NSError *error = nil;
 webdata = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
 if (webdata) {
     return webdata;
 }
 else {
     // Handle error by looking at response and/or error values
     return nil;
 }

Вам больше не понадобится ваш код делегата, если вы используете этот подход. Вы будете ограничены в некоторых отношениях, хотя. Например, если ваша веб-служба требует проверки подлинности с использованием чего-либо, кроме параметров URL, вы не можете использовать этот подход.

0 голосов
/ 16 декабря 2018

Чтобы загрузить данные из webserivce - используйте NSURLSession - Задача сеанса URL, которая возвращает загруженные данные непосредственно в приложение в памяти.

// 1. create NSURL link to your webservice
NSString *dataUrl = @"DATA_LINK_TO_WEBSERVICE";
NSURL *url = [NSURL URLWithString:dataUrl];

// 2. create a NSURLSessionDataTask
NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]
  dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  //Handle response here
}];

// 3.resume the task
[downloadTask resume];

Ссылки:

  1. ссылка на документацию на яблоко: https://developer.apple.com/documentation/foundation/nsurlsessiondatatask?language=objc
  2. Великая кулинарная книга Райвандерлиха: https://www.raywenderlich.com/2392-cookbook-using-nsurlsession
0 голосов
/ 14 января 2012

Вам нужно будет проанализировать возвращаемый XML.Есть несколько хороших анализаторов Objective C XML.В частности, один сделан для простоты использования ....

http://nfarina.com/post/2843708636/a-lightweight-xml-parser-for-ios

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

 NSString *query = [NSString stringWithFormat:@"http://WEB_ADDRESS_FOR_XML];
    NSURL *URL = [NSURL URLWithString:query];
    NSData *data = [NSData dataWithContentsOfURL:URL];

Или с помощью NSURLConnection, в самом деле получают данные:

-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data 
{
    //USE THE DATA RETURNED HERE....
}

Затем используйте парсер из моей ссылкиполучить содержимое:

 SMXMLDocument *document = [SMXMLDocument documentWithData:data error:NULL];

    NSLog("\nXML Returned:%@",document);
0 голосов
/ 14 января 2012

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

Это хороший способ сделать это, если синхронноэто то, что вы хотите:

Все NSURLConnections соединяются асинхронно?Иос

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...