Подтвердить что ты не робот

IOS и ARC: как сохранить себя во время асинхронных операций?

Это первый раз, когда я возился с iOS5 и ARC. Пока, так хорошо, это работает, но я столкнулся с какой-то проблемой.

У меня есть пользовательский UIStoryboardSegue, в котором я использую Facebook Connect (или другие службы) для входа пользователя в мое приложение. Проще говоря, он должен сделать следующее:

  • Пользователь нажимает кнопку
  • Кнопка запускает Segue
  • Сег начинает асинхронный вход, но не сразу нажимает контроллер просмотра
  • Если и только в том случае, если логин успешно завершен, segue выталкивает контроллер вида

Вместо этого происходит то, что вход начинается, но segue сразу же освобождается ARC, прежде чем у него будет шанс завершить.

Я подумал о быстром "грязном взломе", чтобы предотвратить это:

@interface BSLoginSegue() {
    __strong BSLoginSegue *_retained_self;
}
@end

// Stuff...
// Other stuff...

- (void) perform {
    login();
    _retained_self = self;
}

- (void) loginServiceDidSucceed:(BSLoginService *)svc {
    ...
    _retained_self = nil;
}

Дело в том, что это действительно хак, поэтому мне было интересно, есть ли какой-нибудь другой, и более элегантный способ, которым я мог бы сделать то же самое?

4b9b3361

Ответ 1

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

Какой класс несет ответственность за представление segue? Это тот же самый класс, который содержит кнопку? Этот класс должен сохранить segue, представить segue, а затем отпустить segue, когда/если segue завершается.

Без дальнейшего понимания иерархии диспетчера представлений трудно дать конкретные рекомендации. Но моя первая реакция заключается в том, чтобы предположить, что контроллер вида, который решает представить segue или нет, должен иметь сильное свойство на этапе. Подклассовый сегмент может определять протокол, который класс представления может соответствовать, чтобы он был уведомлен о том, когда segue должен быть установлен/освобожден.

Ответ 2

Если вы используете Grand Central Dispatch (GCD) для concurrency (что вам нужно, это потрясающе!), то, поместив ссылку на ваш объект в < блок href= "http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html" > Objective-C и передав его в GCD, он будет автоматически сохранен блоком до тех пор, пока блок не будет выполнен и сам не будет выпущен.

Не зная точно, как вы выполняете операции async, трудно дать окончательный ответ, но используя blocks и GCD вам не придется об этом беспокоиться. Блок будет заботиться о сохранении объектов, которые он ссылается, и ARC сделает все остальное.

Похоже, что вы должны где-то хранить ссылку на свой подкласс UIStoryboardSegue, чтобы называть loginServiceDidSucceed: на нем, поэтому, возможно, просто сделайте, чтобы сильная ссылка работала. И снова ссылка на него с block (например, блок завершения при успешном завершении входа) является идеальной. Я бы рекомендовал адаптировать ваш код входа для использования блоков для обратных вызовов успеха/отказа.

Ответ 3

Просто добавьте и удалите self в/из массива, который является членом данных self следующим образом:

@interface MyClass
{
    NSMutableArray* _selfRetains;
}
@end

@implementation MyClass
-(id)retainSelf
{ 
    [_selfRetains addObject:self];
    return self;
}
-(void)releaseSelf
{
    [_selfRetains removeLastObject];
}
@end

Затем замените [self retain] на [self retainSelf] и [self release] на [self releaseSelf].

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

Ответ 4

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