如何在NSOperation内部启动异步NSURLConnection? [英] How do I start an Asynchronous NSURLConnection inside an NSOperation?

查看:80
本文介绍了如何在NSOperation内部启动异步NSURLConnection?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在后台线程上的NSOperation内执行异步NSURLConnection。
是因为在返回数据时我正在对数据进行一些非常昂贵的操作。

I want to do an Asynchrous NSURLConnection inside of an NSOperation on a background thread. it is because I'm doing some very expensive operations on the data as they come back.

这是一个非常类似的问题,与他们在这里询问的内容类似:
如何在内部执行异步NSURLConnection NSOperation?

This is a very similar question to what they asked here: How do I do an Asynchronous NSURLConnection inside an NSOperation?

,但是区别是我在另一个类中运行连接。

but the difference is that I run the connection in another class.

这是我的第一次尝试:

在我的MainViewController中:

In my MainViewController:

@property (nonatomic, strong) NSOperationQueue *requestQueue;

#pragma mark - Lazy initialization
- (NSOperationQueue *)requestQueue 
{
    if (!_requestQueue) {
        _requestQueue = [[NSOperationQueue alloc] init];
        _requestQueue.name = @"Request Start Application Queue";
        _requestQueue.maxConcurrentOperationCount = 1;
    }
    return _requestQueue;
}

-(void)callToServer
{
URLJsonRequest *request = [URLRequestFactory createRequest:REQUEST_INTERFACE_CLIENT_VERSION
                                                         delegate:self];

    RequestSender *requestSender = [[RequestSender alloc]initWithPhotoRecord:request delegate:self];

   [self.requestQueue addOperation:requestSender];
}

这是我的操作:

- (id)initWithPhotoRecord:(URLJsonRequest *)request
                 delegate:(id<RequestSenderDelegate>) theDelegate{

    if (self = [super init])
    {
        self.delegate = theDelegate;
        self.jsonRequest = request;
    }
    return self;
}

- (void)main {

    //Apple recommends using @autoreleasepool block instead of alloc and init NSAutoreleasePool, because blocks are more efficient. You might use NSAuoreleasePool instead and that would be fine.
    @autoreleasepool
    {

        if (self.isCancelled)
            return;

        [self.jsonRequest start];

    }
}

这是我的Request开始函数:

Here is my Request start function:

-(void) start
{
  NSURL *url = [NSURL URLWithString:@"http://google.com"];
 NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
  urlConnection = [[[NSURLConnection alloc]    initWithRequest:theRequest delegate:self]autorelease];

[urlConnection start];
[theRequest release]
}


- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"Received reponse from connection");
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{



}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{

}

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

}

我没有得到回应

推荐答案

几种方法:


  1. 在主运行循环中使用 startImmediately 参数在主运行循环中安排 NSURLConnection code>否,设置运行循环,然后才应该启动连接,例如:

  1. Schedule the NSURLConnection in the main run loop, by using the startImmediately parameter of NO, set the run loop, and only then should you start the connection, e.g.:

urlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:NO];
[urlConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[urlConnection start];


  • 为连接创建专用线程,并在创建的运行循环中安排连接对于那个线程。有关示例,请参见 AFNetworking 源中的 AFURLConnectionOperation.m

    实际上使用 AFNetworking ,这将为您提供基于 NSOperation 的操作,您可以将其添加到队列中,并为您处理此运行循环。

    Actually use AFNetworking, which gives you NSOperation based operations that you can add to your queue, and takes care of this run loop stuff for you.






    因此,AFNetworking会执行以下操作:


    So, AFNetworking does something like:

    + (void)networkRequestThreadEntryPoint:(id)__unused object {
        @autoreleasepool {
            [[NSThread currentThread] setName:@"NetworkingThread"];
    
            NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
            [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
            [runLoop run];
        }
    }
    
    + (NSThread *)networkRequestThread {
        static NSThread *_networkRequestThread = nil;
        static dispatch_once_t oncePredicate;
    
        dispatch_once(&oncePredicate, ^{
            _networkRequestThread = [[NSThread alloc] initWithTarget:self
                                                            selector:@selector(networkRequestThreadEntryPoint:)
                                                              object:nil];
            [_networkRequestThread start];
        });
    
        return _networkRequestThread;
    }
    

    因此,我执行以下操作。首先,我有一些私有属性:

    So I do something like the following. First I have a few private properties:

    @property (nonatomic, readwrite, getter = isExecuting)  BOOL executing;
    @property (nonatomic, readwrite, getter = isFinished)   BOOL finished;
    @property (nonatomic, weak)   NSURLConnection *connection;
    

    然后,网络操作可以执行以下操作:

    Then the network operation can then do something like:

    @synthesize executing = _executing;
    @synthesize finished  = _finished;
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            _executing = NO;
            _finished = NO;
        }
        return self;
    }
    
    - (void)start {
        if (self.isCancelled) {
            [self completeOperation];
            return;
        }
    
        self.executing = YES;
    
        [self performSelector:@selector(startInNetworkRequestThread)
                     onThread:[[self class] networkRequestThread]
                   withObject:nil
                waitUntilDone:NO];
    }
    
    - (void)startInNetworkRequestThread {
        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request
                                                                      delegate:self
                                                              startImmediately:NO];
        [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
        [connection start];
    
        self.connection = connection;
    }
    
    - (void)completeOperation {
        self.executing = NO;
        self.finished = YES;
    }
    
    - (void)setFinished:(BOOL)finished {
        if (finished != _finished) {
            [self willChangeValueForKey:@"isFinished"];
            _finished = finished;
            [self didChangeValueForKey:@"isFinished"];
        }
    }
    
    - (void)setExecuting:(BOOL)executing {
        if (executing != _executing) {
            [self willChangeValueForKey:@"isExecuting"];
            _executing = executing;
            [self didChangeValueForKey:@"isExecuting"];
        }
    }
    
    - (BOOL)isConcurrent {
        return YES;
    }
    
    - (BOOL)isAsynchronous {
        return YES;
    }
    
    // all of my NSURLConnectionDataDelegate stuff here, for example, upon completion:
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        // I call the appropriate completion blocks here, do cleanup, etc. and then, when done:
    
        [self completeOperation];
    }
    

    这篇关于如何在NSOperation内部启动异步NSURLConnection?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆