Сбой, связанный с ARC в iOS при использовании указателя блока в качестве переменной-члена - PullRequest
3 голосов
/ 13 января 2012

Может кто-нибудь помочь с 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, однако эта часть не важна. Важно то, что происходит, когда apiCallCompletedWithResult вызывается после успешного вызова API. А происходит то, что блок вызывается, но вскоре после этого происходит сбой приложения, когда объект запроса 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 включен для всего проекта.

Ответы [ 2 ]

15 голосов
/ 13 января 2012

Вы хотите, чтобы свойство было copy, а не retain:

@property (nonatomic, copy) APICallOKBlock okCB;
2 голосов
/ 13 января 2012

Вам нужно скопировать блок при сохранении его экземпляра в экземпляр класса.

-(void)addOKBlock:(APICallOKBlock)okBlock
{
    self.okCB = [okBlock copy];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...