块保留它们刚刚传递到的类吗?

发布于 2024-10-30 01:37:21 字数 826 浏览 0 评论 0原文

我们有一个包装 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),并且它在发送后几乎立即开始释放(导致委托)调用已释放对象的方法)。使用同步 NSURLConnection 后,这种情况从未发生过。

我想它会通过异步释放是有道理的,但是我如何适当地保留 request 呢?如果我在创建它后立即保留它,我必须在回调中释放它,但如果请求被取消,回调不会被调用,并且会造成内存泄漏。

We have a class that wraps NSURLConnection. It accepts a block that it calls back when it finishes loading. To give you an idea, see below. When you send a request, it saves the callback on the instance. Assume my class is named Request

// from Request.h
@property (nonatomic, copy) void(^callback)(Request*);
- (void) sendWithCallback:(void(^)(Request*))callback;

My code to use one looks something like this:

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // do some stuff
}]

My question is: what does the block do to the retain count of request? Does it copy/retain it? Notice that I didn't put __block in front of the definition.

I just changed something major in Request (switched from a synchronous NSURLConnection to async ASIHTTPRequest), and it started deallocing almost immediately after sending (causing delegate methods to call a dealloced object). With the sync NSURLConnection, that never happened.

I guess it makes sense that it would get dealloced with async, but how would I retain request appropriately? If I retained it right after I created it, I'd have to release it in the callback, but the callback doesn't get called if the request is cancelled, and would create a memory leak.

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

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

发布评论

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

评论(2

白昼 2024-11-06 01:37:21

该块对请求的保留计数有何作用?它会复制/保留它吗?

不,事实并非如此。

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
}];

what does the block do to the retain count of request? Does it copy/retain it?

No, it doesn't.

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.
}]

If the block doesn't have the request argument,

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^{
    // If you use the request local variable in this block,
    // this block automatically retains the request instance.
}]

In this case, it would cause retain cycles (the request retains the block, the block retains the request).

Please take a look at my AsyncURLConnection class. NSURLConnection retains AsyncURLConnection instance, so you don't own AsyncURLConnection stuff by yourself.

How to use

[AsyncURLConnection request:url completeBlock:^(NSData *data) {
    // Do success stuff
} errorBlock:^(NSError *error) {
    // Do error stuff
}];
木有鱼丸 2024-11-06 01:37:21

块不会自动保留或复制对象参数。它与将对象参数传递给方法或函数的语义相同 - 如果当前自动释放池有可能在块、方法或函数完成使用参数之前耗尽,则块、方法或函数应该保留其参数。

请注意您的场景中的工作流程。此代码:

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // do some stuff
}];

尚未执行该块,也没有向该块传递任何参数。它创建一个块并将其作为参数传递给 -sendWithCallback:。该块有一个名为 request 的参数,类型为 Request *,但实际参数尚未传递。

在代码稍后的某个时刻,假设您已将该块存储在callback中,则该块将被称为:

callback(someRequest); // or callback(self);

or

self.callback(someRequest); // or self.callback(self);

or ,

aRequest.callback(someRequest); // or someRequest.callback(someRequest);

具体取决于谁负责调用它。此时,调用回调的人都应该拥有对有效请求 (someRequest) 的引用,并且该请求是传递给块的参数。

Blocks won’t automatically retain or copy object arguments. It’s the same semantics as passing object arguments to methods or functions — the block, method, or function should retain its arguments if there’s potential for the current autorelease pool to drain before the block, method, or function has finished using the arguments.

Note the workflow in your scenario. This code:

Request * request = [Request requestWithURL:url];
[request sendWithCallback:^(Request * request) {
    // do some stuff
}];

does not execute the block yet, nor does it pass any argument to the block. It creates a block and passes it as an argument to -sendWithCallback:. The block has a parameter called request of type Request * but the actual argument hasn’t been passed yet.

At some point later in your code, and assuming you’ve stored the block in callback, that block will be called as:

callback(someRequest); // or callback(self);

or

self.callback(someRequest); // or self.callback(self);

or

aRequest.callback(someRequest); // or someRequest.callback(someRequest);

depending on who’s responsible for calling it. At this point, whoever calls the callback should have a reference to a valid request (someRequest), and that request is the argument passed to the block.

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