iOS4的实现 - [NSURLConnection sendAsynchronousRequest:queue:completionHandler:]?

问题描述:

如何为iOS < 5实施-[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] 5?iOS4的实现 - [NSURLConnection sendAsynchronousRequest:queue:completionHandler:]?

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 

#import <objc/runtime.h> 
#import "NSURLConnection+iOS4.h" 

// Dynamically add -[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. 
void *sendAsynchronousRequest4(id self, SEL _cmd, NSURLRequest *request, NSOperationQueue *queue, void (^handler)(NSURLResponse*, NSData*, NSError*)); 
void *sendAsynchronousRequest4(id self, SEL _cmd, NSURLRequest *request, NSOperationQueue *queue, void (^handler)(NSURLResponse*, NSData*, NSError*)) { 

    // How should we implement this? 

} 

@implementation NSURLConnection (SendAsync) 

+ (void)load { 
    SEL sendAsyncSelector = @selector(sendAsynchronousRequest:queue:completionHandler:); 
    if (![NSURLConnection instancesRespondToSelector:]) { 
     class_addMethod([self class], sendAsyncSelector, (IMP)sendAsynchronousRequest4, "[email protected]:@@@"); 
    } 
} 

@end 

#endif 

我会去与像ASIHTTPRequest已经建成框架(不再发展,但还是很不错的)或RestKit(我以前从未使用过,但听说它的体面)。这些将在不同版本的OS中为您提供相同的功能(异步HTTP请求)。

ifdefs不是要走的路,因为它们是在编译时完成的,而且您不会为每个平台编译单独的应用程序版本。

你可能会在运行时做一些神秘的工作来让它工作,但它似乎比它的价值更麻烦。

+0

RestKit不支持 KDaker 2013-01-23 01:01:46

我通常做一个NSOperation的子类,并在操作的主要方法内执行同步请求。为了调用这个操作,我创建了一个子类的实例并把它放到一个队列中(而不是主线程)。然后,当操作完成时,它会使用收到的数据调用委托或通过NSNotificationCenter发布通知。

// NSURLConnection+SendAsync.h 

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 

#import <Foundation/Foundation.h> 

@interface NSURLConnection (SendAsync) 

@end 

#endif 


// NSURLConnection+SendAsync.m 

#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 

typedef void (^URLConnectionCompletionHandler)(NSURLResponse *response, NSData *data, NSError *error); 

@interface URLConnectionDelegate : NSObject <NSURLConnectionDataDelegate> 

@property (nonatomic, strong) NSURLResponse *response; 
@property (nonatomic, strong) NSMutableData *data; 
@property (nonatomic, strong) NSOperationQueue *queue; 
@property (nonatomic, copy) URLConnectionCompletionHandler handler; 

@end 

@implementation URLConnectionDelegate 

@synthesize response; 
@synthesize data; 
@synthesize queue; 
@synthesize handler; 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)theResponse { 
    self.response = theResponse; 
    [data setLength:0]; // reset data 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData { 
    [data appendData:theData]; // append incoming data 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
    self.data = nil; 
    if (handler) { [queue addOperationWithBlock:^{ handler(response, nil, error); }]; } 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
    // TODO: Are we passing the arguments to the block correctly? Should we copy them? 
    if (handler) { [queue addOperationWithBlock:^{ handler(response, data, nil); }]; } 
} 

@end 

#import <objc/runtime.h> 
#import "NSURLConnection+SendAsync.h" 

// Dynamically add @property (nonatomic,readonly) UIViewController *presentingViewController. 
void sendAsynchronousRequest4(id self, SEL _cmd, NSURLRequest *request, NSOperationQueue *queue, 
           URLConnectionCompletionHandler handler); 
void sendAsynchronousRequest4(id self, SEL _cmd, NSURLRequest *request, NSOperationQueue *queue, 
           URLConnectionCompletionHandler handler) { 

    URLConnectionDelegate *connectionDelegate = [[URLConnectionDelegate alloc] init]; 
    connectionDelegate.data = [NSMutableData data]; 
    connectionDelegate.queue = queue; 
    connectionDelegate.handler = handler; 
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request 
                   delegate:connectionDelegate]; 
    NSAssert(connection, nil); 
} 

@implementation NSURLConnection (SendAsync) 

+ (void)load { 
    SEL sendAsyncSelector = @selector(sendAsynchronousRequest:queue:completionHandler:); 
    if (![NSURLConnection instancesRespondToSelector:sendAsyncSelector]) { 
     class_addMethod(object_getClass([self class]), 
         sendAsyncSelector, (IMP)sendAsynchronousRequest4, "[email protected]:@@@"); 
    } 
} 

@end 

#endif 
+0

嘿马特,有没有这个代码的某个版本的github或类似的地方?这将是很好的,让人们可以轻松地提交错误修复和改进 – Andrea 2012-07-20 22:57:26

+0

而不是'instancesRespondToSelector',我们不应该使用'respondsToSelector'?我们正在检查类方法的存在。 – adbie 2013-01-08 09:33:57