2014-09-04 3 views
0

Я создаю приложение для iPhone, которое сильно использует веб-сервис, который я написал на php. Прямо сейчас у меня есть файл (API.h/API.m), который имеет методы, которые вызывают функции php на моем веб-сервисе через NSURLConnection.Существуют ли более чистые методы обработки асинхронных HTTP-запросов, чем делегирование в Objective-C?

методы, такие как:

-(void) mediaAdd:(UIImage *)image withDelegate: (id<apiRequest>) delegate; 
-(void) mediaGet:(NSString *)imageURL withDelegate: (id<apiRequest>) delegate; 

Эти методы называются контроллерами в приложении (контроллеры, определенные в шаблоне MVC), а также методы принимают в контроллере в качестве делегата.

Как только запрос вызванного метода в API.h/API.m завершен, метод делегата NSURLConnection в API.h/API.m, который вызывается, когда запрос завершен, затем вызывает метод делегирования. .

-(void) serverResponse:(NSDictionary *) response fromCall:(NSString *)call; 

... который, конечно, выполняется на контроллере, который вызывает метод в API.h/API.m.

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

Вот скелет экземпляра метода serverResponse:

//API Delegate 
-(void)serverResponse:(NSDictionary *)response fromCall:(NSString *)call { 
    bool local = false; 
    NSString *callbackString; 
    if (local) { 
     callbackString = @"http://localhost/"; 
    } else { 
     callbackString = @"http://secret.com/"; 
    } 
    if ([call isEqualToString:[NSString stringWithFormat:@"%@user/add",callbackString]]) { 
     //user/add was called 
     if (![[response objectForKey:@"status"] isEqualToString:@"fail"]) { 
      if ([[response objectForKey:@"status"] isEqualToString:@"fail"]) { 
       if ([[response objectForKey:@"reason"] isEqualToString:@"udid already taken"]) { 
        //UDID taken 
       } 
      } else { 

       //UDID not taken, we're good to go 



      } 

     } else { 
      NSLog(@"fail"); 
     } 
    } else if([call isEqualToString:[NSString stringWithFormat:@"%@moment/get",callbackString]]){ 
     //moment/get was the api call 
    } else if([call isEqualToString:[NSString stringWithFormat:@"%@printPictures/printPic",callbackString]]){ 

     //printPictures/printPic was the api call 
    } else { 
     NSLog(@"wrong call"); 
    } 



} 

Мой вопрос, я должен идти вперед и сделать решительный шаг сделать метод делегата для каждого вызова API? Или я переусердствую об этом, и на самом деле есть действительно простой способ справиться с этим. Возможно, шаблон дизайна или структура?

Спасибо! - Mike

+0

Отслеживание темы, но теперь, глядя на скелет, у меня много избыточного кода .. ха-ха. Просто заметив, что я замечаю это, я знаю, что это проблема. –

+0

Вы можете передать блок завершения вместо делегата. –

+0

Вы понимаете, что вы можете создать более одного делегата * объекта * для данного протокола делегата? Чтобы решить вашу проблему, просто создайте объект для каждого вызова API. –

ответ

2

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

Downloader *dl = [Downloader new]; 
    NSURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"...."]] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10]; 

    [dl downloadWithRequest:(NSURLRequest *) request completion:^(NSData *data, NSError *error) { 
     if (!error) { 
      // do whatever you need to do with the raw data here 
      NSLog(@"got the data"); 
     }else{ 
      NSLog(@"%@",error); 
     } 
    }]; 

Вот как я реализовал класс Downloader.

typedef void(^compBlock)(NSData *data, NSError *error); 

@interface Downloader : NSObject <NSURLConnectionDataDelegate> 

-(void)downloadWithRequest:(NSURLRequest *) request completion:(compBlock) completion; 

@end 

Файл реализации,

@interface Downloader() 
@property (copy,nonatomic) compBlock completionHandler; 
@property (strong,nonatomic) NSMutableData *receivedData; 
@end 

@implementation Downloader 

-(void)downloadWithRequest:(NSURLRequest *) request completion:(compBlock)completion { 
    NSURLConnection *con = [NSURLConnection connectionWithRequest:request delegate:self]; 
    if (con) { 
     self.receivedData = [NSMutableData new]; 
     self.completionHandler = completion; 
    } 
} 


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
    self.receivedData.length = 0; 
} 



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



-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 
    self.completionHandler(nil, error); 
} 



-(void)connectionDidFinishLoading:(NSURLConnection *)connection { 
    self.completionHandler(self.receivedData, nil); 
} 
+0

Разве этот метод не требует синхронного запроса? Или, может быть, синхронный запрос в другой очереди? –

+0

@MichaelKing, нет, в классе Downloader я использую NSURLConnection с обычными методами делегирования. Блок обратного вызова вызывается в файле didFailWithError или connectionDidFinishLoading. – rdelmar

+0

Я не понимал, что блоки обратного вызова могут находиться в отдельном месте. Думаю, мне нужно больше узнать о блоках и о том, как они работают. У вас есть какие-то хорошие ресурсы? –

0

Моя проблема, а точнее дезорганизации возникает, когда контроллер должен сделать более одного вызова API.

Для такого рода вещей вы действительно должны посмотреть на NSURLSession и связанные классы. NSURLSession предоставляет методы, такие как -sendAsynchronousRequest:queue:completionHandler:, которые позволяют выполнять задачи без необходимости предоставления собственного объекта делегирования - сеанс предоставит вам делегат по умолчанию, а делегат по умолчанию вызовет ваш обработчик завершения, когда задача будет выполнена.

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

Я не буду вдаваться в все преимущества NSURLSession, потому что вы можете read about them самостоятельно, но они значительны. Если вы пишете новый код, вы почти наверняка должны использовать NSURLSession вместо NSURLConnection.

 Смежные вопросы

  • Нет связанных вопросов^_^