35

是否建议将 NSUrlConnection 包装在 gcd 样式块中并在 low_priority 队列上运行它?

我需要确保我的连接不会发生在主线程上,并且连接需要是异步的。我还需要同时发出几个请求。

如果我走 gcd 路线,我不确定 NSUrlConnectionDelegate 方法在哪个线程上被调用。

NSURLConnection 依赖于委托,所以一旦连接完成,任何处理它的包装类都需要调用它的调用者。我不确定如何处理连接工作启动/完成时调用的所有各种回调:

- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)incrementalData;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

我应该只调用同步版本但包装在 gcd 块中吗?如果我想取消通话,请使用“dispatch_suspend”?

dispatch_async(queue,^{
      NSString* result = [self mySynchronousHttp:someURLToInvoke];
      });

// If I need to cancel
dispatch_suspend(queue);
4

3 回答 3

53

我建议您查看有关 iPhone OS 中网络应用程序的 WWDC 会议。

  • WWDC 2010 Session 207 - iPhone OS 的网络应用程序,第 1 部分
  • WWDC 2010 Session 208 - iPhone OS 的网络应用程序,第 2 部分

讲师说

“线程是邪恶的™”

用于网络编程,建议使用带有 RunLoop 的异步网络编程。使用后台线程(Grand Central Dispatch Concurrent Queue)进行线程安全的数据处理,而不是用于网络编程。

顺便说一句,Blocks 和 Grand Central Dispatch 会议也值得一看。

  • WWDC 2010 Session 206 - 在 iPhone 上介绍 Blocks 和 Grand Central Dispatch
  • WWDC 2010 Session 211 - 使用 Grand Central Dispatch 简化 iPhone 应用程序开发

我为异步 NSURLConnection 编写了一个包装类。


AsyncURLConnection.h

#import <Foundation/Foundation.h>

typedef void (^completeBlock_t)(NSData *data);
typedef void (^errorBlock_t)(NSError *error);

@interface AsyncURLConnection : NSObject
{
    NSMutableData *data_;
    completeBlock_t completeBlock_;
    errorBlock_t errorBlock_;
}

+ (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
- (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
@end

AsyncURLConnection.m

#import "AsyncURLConnection.h"

@implementation AsyncURLConnection

+ (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{
    return [[[self alloc] initWithRequest:requestUrl
        completeBlock:completeBlock errorBlock:errorBlock] autorelease];
}

- (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
{

    if ((self=[super init])) {
        data_ = [[NSMutableData alloc] init];

        completeBlock_ = [completeBlock copy];
        errorBlock_ = [errorBlock copy];

        NSURL *url = [NSURL URLWithString:requestUrl];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [NSURLConnection connectionWithRequest:request delegate:self];
    }

    return self;
}

- (void)dealloc
{
    [data_ release];

    [completeBlock_ release];
    [errorBlock_ release];
    [super dealloc];
}

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

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

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    completeBlock_(data_);
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    errorBlock_(error);
}

@end

如何使用 AsyncURLConnection 类。

/*
 * AsyncURLConnection -request:completeBlock:errorBlock: have to be called
 * from Main Thread because it is required to use asynchronous API with RunLoop.
 */

[AsyncURLConnection request:url completeBlock:^(NSData *data) {

    /* success! */

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        /* process downloaded data in Concurrent Queue */

        dispatch_async(dispatch_get_main_queue(), ^{

            /* update UI on Main Thread */

        });
    });

} errorBlock:^(NSError *error) {

    /* error! */

}];
于 2011-03-01T06:57:21.893 回答
1

创建一个并发的 NSOperation,在它上面运行你的异步 NSURLConnection。

于 2011-02-19T11:36:45.393 回答
0

看看这个代码块:

-(void)getDataFromServer
{
    NSDictionary *dicParams = [NSDictionary dictionaryWithObjectsAndKeys:
                           userId,    kUserID,
                           pageIndex,kPageIndex,
                           nil];

    NSString *yourURL = [self addQueryStringToUrlString:[NSString stringWithFormat:@"%@/%@",_PATH_,apiName] withDictionary:dicParams];


    NSString *queue_id = @"_queue_id_";
    dispatch_queue_t queue = dispatch_queue_create([queue_id UTF8String], 0);
    dispatch_queue_t main = dispatch_get_main_queue();

    dispatch_async(queue, ^{

        NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:yourURL] 
                                                    cachePolicy:NSURLRequestReloadIgnoringCacheData 
                                                timeoutInterval:60.0];
        [theRequest setHTTPMethod:@"GET"];
        [theRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [theRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

        NSError        *serviceError = nil;
        NSURLResponse  *serviceResponse = nil;
        NSData *dataResponse = [NSURLConnection sendSynchronousRequest:theRequest 
                                                     returningResponse:&serviceResponse 
                                                                 error:&serviceError];

        if(serviceError)
        {
            dispatch_sync(main, ^{

                // Update your UI

                if(serviceError.code == -1012){
                    // Log error
                }else{
                    // Log error
                }
            });
        }

        else
        {
            NSError *jsonError = nil;

            id dataObject = [NSJSONSerialization JSONObjectWithData:dataResponse 
                                                            options:kNilOptions 
                                                              error:&jsonError];
            NSMutableArray *arrResponse = (NSMutableArray *)dataObject;

            dispatch_sync(main, ^{

                // Update your UI
                [yourTableView reloadData];
            });
        }
    });
}

+(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary
{
    NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString];

    for (id key in dictionary) {
        NSString *keyString = [key description];
        NSString *valueString = [[dictionary objectForKey:key] description];

        if ([urlWithQuerystring rangeOfString:@"?"].location == NSNotFound) {
            [urlWithQuerystring appendFormat:@"?%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
        } else {
            [urlWithQuerystring appendFormat:@"&%@=%@", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
        }
    }
    return urlWithQuerystring;
}

+(NSString*)urlEscapeString:(NSString *)unencodedString
{
    CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString;
    NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, NULL,kCFStringEncodingUTF8);
    CFRelease(originalStringRef);
    return s;
}
于 2015-07-31T12:50:35.353 回答