使用块指针作为成员变量时,iOS 中与 ARC 相关的崩溃

发布于 2024-12-26 13:21:00 字数 2295 浏览 1 评论 0原文

谁能帮忙解决 ARC 和内存相关的崩溃问题吗?

我有类 LTRequest ,它有一个存储块指针的成员变量:

typedef void (^APICallOKBlock)(id);

@interface LTRequest : NSObject
@property (nonatomic, strong) APICallOKBlock okCB;
@end

初始化该变量的代码:

-(void)addOKBlock:(APICallOKBlock)okBlock
{
    self.okCB = okBlock;
}

如果成功,我调用该块:

-(void)apiCallCompletedWithResult:(id)result
{
    if(self.okCB != nil)
    {
        self.okCB(result);
    }
}

作为参考,该块看起来像这样:

APICallOKBlock okBlock = ^(id result)
{
    [self handleAPICallCompleted:result];
};

它调用调度 api 调用的对象中定义的函数,但这部分并不重要。重要的是在 api 调用成功后调用 apiCallCompletedWithResult 时会发生什么。发生的情况是,该块被调用,但当请求对象 LTRequest 被释放时应用程序很快崩溃(SomeAppName 是我们的应用程序):

Thread 6 name:  Dispatch queue: com.apple.root.low-priority
Thread 6 Crashed:
0   libobjc.A.dylib                 0x300bad9c objc_release + 12
1   libobjc.A.dylib                 0x300c6c00 objc_storeStrong + 24
2   SomeAppName                     0x00055688 -[LTRequest .cxx_destruct] (LTRequest.m:12)
3   libobjc.A.dylib                 0x300bba66 object_cxxDestructFromClass + 50
4   libobjc.A.dylib                 0x300bba2c object_cxxDestruct + 8
5   libobjc.A.dylib                 0x300b99ac objc_destructInstance + 20

我尝试使用 unsafe_unretained 而不是strong 将块存储在 LTRequest 对象中:

@property (nonatomic, unsafe_unretained) APICallOKBlock okCB;

在这种情况下,崩溃恰好发生在 if 的行中:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x300b9eda objc_retain + 10
1   libobjc.A.dylib                 0x300c6bde objc_retainAutoreleasedReturnValue + 34
2   SomeAppName                     0x00054f90 -[LTRequest apiCallCompletedWithResult:] (LTRequest.m:84)
3   SomeAppName                     0x0002f8aa __29-[LTServerProxy makeAPICall:]_block_invoke_0 (LTServerProxy.m:154)

// file LTRequest.m

line 84    if(self.okCB != nil)
line 85    {
line 86        self.okCB(result);
line 87    }

我是否正确使用了指向块的指针以及应该如何使用我称其为不引起任何崩溃?

一些信息:我使用的是 iOS SDK 5.0,部署目标是 4.0,设备 iPhone,并且为整个项目启用了 ARC。

Can anyone please help with ARC and memory-related crashes?

I have class LTRequest with a member variable that stores a block pointer:

typedef void (^APICallOKBlock)(id);

@interface LTRequest : NSObject
@property (nonatomic, strong) APICallOKBlock okCB;
@end

The code to initialize that variable:

-(void)addOKBlock:(APICallOKBlock)okBlock
{
    self.okCB = okBlock;
}

I call the block in case of success:

-(void)apiCallCompletedWithResult:(id)result
{
    if(self.okCB != nil)
    {
        self.okCB(result);
    }
}

For reference, the block looks something like this:

APICallOKBlock okBlock = ^(id result)
{
    [self handleAPICallCompleted:result];
};

It calls a function defined in the object that scheduled the api call, however that part is not important. Important is what happens when apiCallCompletedWithResult is called after the api call has been successful. And what happens is that the block gets called but the app crashes shortly afterwards when the request object LTRequest gets deallocated (SomeAppName is our application):

Thread 6 name:  Dispatch queue: com.apple.root.low-priority
Thread 6 Crashed:
0   libobjc.A.dylib                 0x300bad9c objc_release + 12
1   libobjc.A.dylib                 0x300c6c00 objc_storeStrong + 24
2   SomeAppName                     0x00055688 -[LTRequest .cxx_destruct] (LTRequest.m:12)
3   libobjc.A.dylib                 0x300bba66 object_cxxDestructFromClass + 50
4   libobjc.A.dylib                 0x300bba2c object_cxxDestruct + 8
5   libobjc.A.dylib                 0x300b99ac objc_destructInstance + 20

I tried to use unsafe_unretained instead of strong to store the block in the LTRequest object:

@property (nonatomic, unsafe_unretained) APICallOKBlock okCB;

In that case the crash happens exactly in the line with the if:

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x300b9eda objc_retain + 10
1   libobjc.A.dylib                 0x300c6bde objc_retainAutoreleasedReturnValue + 34
2   SomeAppName                     0x00054f90 -[LTRequest apiCallCompletedWithResult:] (LTRequest.m:84)
3   SomeAppName                     0x0002f8aa __29-[LTServerProxy makeAPICall:]_block_invoke_0 (LTServerProxy.m:154)

// file LTRequest.m

line 84    if(self.okCB != nil)
line 85    {
line 86        self.okCB(result);
line 87    }

Am I using the pointer to a block properly and how should I call it to not cause any crashes?

Some info: I am using iOS SDK 5.0, deployment target is 4.0, device iPhone, and ARC is enabled for the whole project.

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

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

发布评论

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

评论(2

恍梦境° 2025-01-02 13:21:00

您希望该属性是copy而不是retain

@property (nonatomic, copy) APICallOKBlock okCB;

You want the property to be copy rather than retain:

@property (nonatomic, copy) APICallOKBlock okCB;
走过海棠暮 2025-01-02 13:21:00

将块的实例保存到类实例时,您需要复制该块。

-(void)addOKBlock:(APICallOKBlock)okBlock
{
    self.okCB = [okBlock copy];
}

You need to copy the block when saving its instance to the class instance.

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