Реализация iOS4 - [NSURLConnection sendAsynchronousRequest: очередь: завершениеHandler:]? - PullRequest
3 голосов
/ 23 марта 2012

Как я могу реализовать -[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] для iOS <5? </p>

#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, "v@:@@@");
    }
}

@end

#endif

Ответы [ 3 ]

3 голосов
/ 24 марта 2012
// 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, "v@:@@@");
    }
}

@end

#endif
0 голосов
/ 23 марта 2012

Я обычно делаю подкласс NSOperation и делаю запрос синхронизации внутри основного метода операции.Чтобы вызвать операцию, я создаю экземпляр подкласса и помещаю его в очередь (а не в основной поток).Затем, когда операция завершается, она либо вызывает делегата с полученными данными, либо отправляет уведомление через NSNotificationCenter.

0 голосов
/ 23 марта 2012

Я бы пошел с уже созданным фреймворком, таким как ASIHTTPRequest (больше не разрабатывается, но все еще очень хорошо) или RestKit (я никогда не использовал его раньше, но слышал, что он приличный).Они предоставят вам одинаковую функциональность (асинхронные http-запросы) в разных версиях ОС.

ifdefs - это не тот способ, так как они сделаны во время компиляции, и вы не будете компилировать отдельные версииприложения для каждой платформы.

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

...