我们有一个包装NSURLConnection的类。它接受一个在完成加载时回调的块。给你一个想法,见下文。发送请求时,它会在实例上保存回调。假设我的班级名为Request
// from Request.h
@property (nonatomic, copy) void(^callback)(Request*);
- (void) sendWithCallback:(void(^)(Request*))callback;
我使用的代码看起来像这样:
Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
// do some stuff
}]
我的问题是:该块对request
的保留计数有何影响?它复制/保留吗?请注意,我没有将__block
放在定义的前面。
我刚刚更改了Request
中的一些主要内容(从同步NSURLConnection
切换到异步ASIHTTPRequest
),并且在发送后几乎立即开始解除分配(导致委托方法调用dealloced对象) )。使用同步NSURLConnection
,从未发生过。
我认为它会被异步释放,但我如何恰当地保留request
?如果我在创建它之后立即保留它,我必须在回调中释放它,但是如果请求被取消则不会调用回调,并且会产生内存泄漏。
答案 0 :(得分:2)
该块对保留请求计数的作用是什么?是复制还是保留它?
不,它没有。
Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
// The request argument shadows the request local variable,
// this block doesn't retain the request instance.
}]
如果块没有请求参数,
Request * request = [Request requestWithURL:url];
[request sendWithCallback:^{
// If you use the request local variable in this block,
// this block automatically retains the request instance.
}]
在这种情况下,它会导致保留周期(请求保留块,块保留请求)。
请查看我的AsyncURLConnection类。 NSURLConnection保留AsyncURLConnection实例,因此您不需要自己拥有AsyncURLConnection。
如何使用
[AsyncURLConnection request:url completeBlock:^(NSData *data) {
// Do success stuff
} errorBlock:^(NSError *error) {
// Do error stuff
}];
答案 1 :(得分:0)
块不会自动保留或复制对象参数。它与将对象参数传递给方法或函数的语义相同 - 如果在块,方法或函数使用参数完成之前,当前自动释放池有可能耗尽,则块,方法或函数应保留其参数。
请注意您方案中的工作流程。这段代码:
Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
// do some stuff
}];
尚未执行该块,也不会将任何参数传递给该块。它创建一个块并将其作为参数传递给-sendWithCallback:
。该块有一个名为request
的{{1}}类型的参数,但实际参数尚未通过。
稍后在您的代码中,并假设您已将块存储在Request *
中,该块将被调用为:
callback
或
callback(someRequest); // or callback(self);
或
self.callback(someRequest); // or self.callback(self);
取决于谁负责调用它。此时,无论谁调用回调都应该引用有效请求(aRequest.callback(someRequest); // or someRequest.callback(someRequest);
),该请求是传递给块的参数。