Кластер классов с ARC

Я пытаюсь создать кластер классов в качестве подкласса UIViewController для достижения некоторых пунктов:

1. Различное поведение ViewController в зависимости от актуальной версии iOS

2. Проверки версии iOS не загромождают код

3. Абоненту не нужно заботиться

Пока я получил классы MyViewController, MyViewController_iOS7 а также MyViewController_Legacy,

Для создания экземпляров я вызываю метод myViewControllerWithStuff:(StuffClass*)stuff который реализован как:

+(id)myViewControllerWithStuff:(StuffClass*)stuff
{
    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1)
    {
        return [[MyViewController_iOS7 alloc] initWithStuff:stuff];
    }
    else
    {
        return [[MyViewController_Legacy alloc] initWithStuff:stuff];
    }
}

Вызывающая сторона использует myViewControllerWithStuff:, После этого созданный таким образом контроллер представления выдвигается на UINavigationControllerНавигационный стек.

Это почти работает, как и предполагалось, с одним большим недостатком: ARC не освобождает экземпляр MyViewController_xxx когда он выскочил из стека навигации. Не имеет значения, какая версия iOS.

Что мне не хватает?

ОБНОВЛЕНИЕ: -initWithStuff:

-(id)initWithStuff:(StuffClass*)stuff
{
    if (self = [super init])
    {
        self.stuff = stuff;
    }

    return self;
}

Этот метод также реализован в MyViewController, Различия всплывают позже (например, viewDidLoad:).

1 ответ

Решение

Прежде всего: спасибо за вашу помощь, комментарии, ответы, предложения...

Конечно был другой strong ссылка на MyViewController-объект. Но это было не так очевидно, потому что это не было свойством или переменной экземпляра.

В viewDidLoad Я сделал следующее:

[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    [self saveState];
}];

Это должно предотвратить потерю данных в случае, если пользователь отправляет приложение в фоновый режим. Конечно, блок захватывает необходимые части своего окружения. В этом случае он захватил self, Блок держит self жив, пока он (блок) не будет уничтожен, как, например, [[NSNotificationCenter defaultCenter] removeObserver:self]; вызывается. Но, не повезло, этот звонок помещен в dealloc метод MyViewController который не будет вызван, пока существует блок...

Исправление заключается в следующем:

__weak MyViewController *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
    [weakSelf saveState];
}];

Теперь блок захватывает weakSelf, Таким образом, он не может держать MyViewController-объект живой и все освобождает и работает просто отлично.

Другие вопросы по тегам