是否有比 Objective-C 中的委托更简洁的方法来处理异步 http 请求?

问题描述 投票:0回答:2

我正在构建一个 iPhone 应用程序,该应用程序大量利用了我用 PHP 编写的 Web 服务。现在我有一个文件 (API.h/API.m),其中包含通过

NSURLConnection
.

调用我的 Web 服务上的 PHP 函数的方法

方法如下:

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

这些方法由应用程序中的控制器(MVC 模式定义的控制器)调用,并且这些方法将控制器作为委托。

一旦 API.h/API.m 中被调用方法的请求完成,请求完成时调用 API.h/API.m 中的

NSURLConnection
委托方法,然后调用该委托方法...

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

...当然是在调用 API.h/API.m 中的方法的控制器上执行的。

当控制器需要进行多个 API 调用时,就会出现我的问题,或者更确切地说是混乱。因为我只有单个委托方法,所以我通过使用

serverResponse
方法中的 call 参数来区分不同的调用。

这是

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 调用创建一个委托方法?或者我想得太多了,实际上有一个非常简单的方法来处理这个问题。也许是设计模式或结构?

ios objective-c nsurl delegation
2个回答
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
投票

当控制器需要进行多个 API 调用时,就会出现我的问题,或者更确切地说是混乱。

对于这种事情,你真的应该看看

NSURLSession
和相关的类。
NSURLSession
提供类似
-sendAsynchronousRequest:queue:completionHandler:
的方法,让您无需提供自己的委托对象即可完成任务 - 会话将为您提供默认委托,默认委托将在任务完成时调用您的完成处理程序。

当然,您仍然可以选择提供自己的委托,并且每个任务都有一个标识符,以便您的委托可以比您使用

NSURLConnection
更轻松地跟踪哪个任务是哪个任务。

我不会在这里详细介绍

NSURLSession
的所有好处,因为您可以自己阅读它们,但它们很重要。如果您正在编写新代码,您几乎肯定应该使用
NSURLSession
而不是
NSURLConnection

© www.soinside.com 2019 - 2024. All rights reserved.