NSOperation 中的块

发布于 2025-01-05 18:12:14 字数 1429 浏览 0 评论 0 原文

我使用 AFNetworking 执行 URL 请求并在 NSOperation 中定义成功/错误块 - 所以这基本上是在 NSOperation 中运行异步进程。

我理解这种方法背后的警告,因为 NSOperation 会在调用委托方法之前提前终止,因此通过在主线程上运行 start() 来实现建议的解决方案之一(相关帖子 NSOperation 中的异步方法)。

到目前为止,一切都很好,我可以看到执行顺序是正确的,即成功块执行,完成,然后调用 dealloc。直到有一个名为 __destroy_helper_block 的(系统?)线程引用 NSOperation 中的成功块,该块在此阶段已被释放。这到底是什么? AFNetworking 是否持有对该块的引用?

该线程上的调用堆栈是:

objc_release
_destroy_helper_block
_区块_释放
__destroy_helper_block
_区块_释放
start_wqthread

代码是

- (void) start {
    ...
    void (^successHandler)(NSURLRequest *, NSHTTPURLResponse*, NSXMLParser *) = ^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
    URLRequestParserDelegate *parserDelegate = [[URLRequestParserDelegate alloc]initWithChildDelegate:self];

        // child to handle connection success
        [self handleSuccess:request response:response];

        // parse xml response data
        [XMLParser setDelegate:parserDelegate];     
        [XMLParser parse];
        [parserDelegate release];
        [self finish];
    }; // EXC_BAD_ACCESS on this line (?)

    AFXMLRequestOperation *op = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
    success:successHandler failure:nil];
    [op start];
}

I'm using AFNetworking to perform URL request and defining success/error blocks within NSOperation - so that's basically running asynchronous process within NSOperation.

I understand the caveat behind this approach, being NSOperation would terminate prematurely before delegate methods are called and therefore have implemented one of the suggested solutions by running start() on the main thread (relevant post Asynchronous methods in NSOperation).

So far that's all good, I can see that the order of execution is correct i.e. success block executes, done, then dealloc gets called. UNTIL there's this (system?) thread called __destroy_helper_block that is referencing success block in the NSOperation which at this stage has been dealloc'd. What exactly is this? Is AFNetworking holding reference to the block?

Call stack on that thread is:

objc_release
_destroy_helper_block
_Block_release
__destroy_helper_block
_Block_release
start_wqthread

Code is

- (void) start {
    ...
    void (^successHandler)(NSURLRequest *, NSHTTPURLResponse*, NSXMLParser *) = ^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
    URLRequestParserDelegate *parserDelegate = [[URLRequestParserDelegate alloc]initWithChildDelegate:self];

        // child to handle connection success
        [self handleSuccess:request response:response];

        // parse xml response data
        [XMLParser setDelegate:parserDelegate];     
        [XMLParser parse];
        [parserDelegate release];
        [self finish];
    }; // EXC_BAD_ACCESS on this line (?)

    AFXMLRequestOperation *op = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
    success:successHandler failure:nil];
    [op start];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蘸点软妹酱 2025-01-12 18:12:14

我只知道使用 ASINetworkQueue 可以轻松完成此操作:

- (void) process {

    //Create downloadQueue
    if (![self queue]) {
        [self setQueue:[[[ASINetworkQueue alloc] init] autorelease]];
        [[self queue] setDelegate:self];
        [[self queue] setShouldCancelAllRequestsOnFailure:NO];
        [[self queue] setQueueDidFinishSelector:@selector(queueFinished:)];
    }

    [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://www.YOURURL.com/"]];
    [[self queue] addOperation:request]; //queue is an NSOperationQueue
    NSLog(@"request added to operation");

    [request setCompletionBlock:^{

        NSLog(@"response headers %@", [request responseHeaders]);
        NSLog(@"response body %@", [request responseString]);

    }];

    [request setFailedBlock:^{

        NSLog(@"response error: %@", [[request error] localizedDescription]);

    }];
}

- (void)queueFinished:(ASINetworkQueue *)queue{
    NSLog(@"queueFinished:");
}  

I only know this is easily done with the ASINetworkQueue:

- (void) process {

    //Create downloadQueue
    if (![self queue]) {
        [self setQueue:[[[ASINetworkQueue alloc] init] autorelease]];
        [[self queue] setDelegate:self];
        [[self queue] setShouldCancelAllRequestsOnFailure:NO];
        [[self queue] setQueueDidFinishSelector:@selector(queueFinished:)];
    }

    [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://www.YOURURL.com/"]];
    [[self queue] addOperation:request]; //queue is an NSOperationQueue
    NSLog(@"request added to operation");

    [request setCompletionBlock:^{

        NSLog(@"response headers %@", [request responseHeaders]);
        NSLog(@"response body %@", [request responseString]);

    }];

    [request setFailedBlock:^{

        NSLog(@"response error: %@", [[request error] localizedDescription]);

    }];
}

- (void)queueFinished:(ASINetworkQueue *)queue{
    NSLog(@"queueFinished:");
}  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文