Подсчет ссылок при реализации делегата для пользовательского класса в ObjectiveC - PullRequest
2 голосов
/ 08 июня 2009

У меня есть два класса, ClassA, который будет создавать экземпляр ClassB и выдавать метод в качестве делегата. ClassB в конечном итоге вызовет делегата ClassA. Нужно ли добавлять сохранение в ClassA, когда ClassB хранит его?

Я следую «Реализации делегата для пользовательского класса» из «Руководства по основам какао: общение с объектами», но показанный пример кода, похоже, не учитывает управление памятью.

ClassA установит делегата и будет ожидать его повторного вызова позже, когда ClassB завершит свою работу.

@implementation ClassA

-(void)launchSomething
{
   ClassB *classB = [[ClassB alloc] init];
   [classB setCallback:self withSelector:@selector(deferredWork)];

   // do some other stuff, assign class B to some View and eventually release class B
}

-(void)deferredWork
{
   NSLog(@"this is the method that will be deferred till some point in time");
}

Заголовочный файл для ClassB, который будет хранить, а затем вызывать делегат:

@interface ClassB

id targetObject;
SEL targetMethod;

-(void) setCallback:(id)anObject withSelector:(SEL)aMethod

Реализация класса B:

@implementation ClassB
-(void) setCallback:(id)anObject withSelector:(SEL)aMethod
{
   // QUESTION: Do I need to add a 'retain' here on the targetObject?
   targetObject = anObject;
   targetMethod = aMethod;
}

-(void) someWorkLater
{
    if ( [targetObject respondsToSelector:@selector(targetMethod)] ) {
        // invoke the target object with the specific method
        [targetObject targetMethod];
    }
}

Ответы [ 2 ]

2 голосов
/ 09 июня 2009

Вы не оставите ClassA в ClassB, потому что ClassA уже владеет ClassB, и предполагается, что когда ClassA будет освобожден, он позаботится об очистке любых ссылок в ClassB.

Если вы следовали «обычным» правилам владения и сохранили ClassA при установке метода делегата в ClassB, вы бы получили цикл сохранения, в котором ни один объект никогда не был бы освобожден. Вместо этого вы должны использовать слабую ссылку точно так же, как вы.

0 голосов
/ 09 июня 2009

Как сказал Марк, обычная практика в Какао состоит в том, чтобы делегаты были "слабыми" звеньями. То есть они не сохраняются. Именно делегат должен гарантировать, что когда он больше не сможет отвечать как delagate, ничего плохого не случится - либо установив делегат равным nil, либо освободив исходный объект (при условии, что он является единственным владельцем и будет немедленно освобожден) .

Так что в вашем примере, если classB остается после окончания launchSomething, то вы, вероятно, сохранили его в ivar. Ваша процедура деллок для класса А будет иметь либо

[classB setCallback:nil]; // optionally withSelector:@selector(none)

и / или

[classB release];

Если у classB могут быть другие владельцы, вам определенно следует использовать setCallback: nil, но часто вы знаете, что являетесь единственным владельцем.

Ситуация усложняется, когда задействованы представления и окна, поскольку может быть сложно обеспечить освобождение объектов заказа и что никто другой не имеет сильной связи с классом B, и в этом случае очистка обратного вызова необходима.

То же самое относится к наблюдателям и уведомлениям, которые, как правило, являются слабыми звеньями и поэтому должны быть очищены в вашей процедуре dealloc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...