2015-03-21 2 views
2

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

я первоначально определен метод в AppDelegate:

- (void)displayViewcontroller:(NSViewController *)viewController { 
    BOOL ended = [self.window makeFirstResponder:self.window]; 
    if (!ended) { 
     NSBeep(); 
     return; 
    } 
    [self.box setContentView:viewController.view]; 
} 

мне определить цель/действие для NSButton к AppDelegate, и вот где я называю этот метод, чтобы показать новый контроллер представления:

- (IBAction)didTapContinue:(NSButton *)sender { 
    NewViewController *newVC = [[NewViewController alloc] init]; 
    [self displayViewcontroller:newVC]; 
} 

Это делает работу - она ​​представляет собой вид контроллера нового вида. Однако, если я затем нажимаю любую кнопку в этом представлении, у которой есть целевая/действительная настройка, которая находится внутри класса контроллера класса, приложение моментально падает.

Чтобы решить эту проблему, я должен изменить didTapContinue: на следующее:

- (IBAction)didTapContinue:(NSButton *)sender { 
    NewViewController *newVC = [[NewViewController alloc] init]; 
    [self.viewControllers addObject:newVC]; 
    [self displayViewcontroller:[self.viewControllers lastObject]]; 
} 

Прежде всего, вы можете объяснить, почему это решает проблему? Кажется, это связано с тем, как контроллер «удерживается» в памяти, но я не уверен.

Мой вопрос: как мне настроить это, чтобы я мог менять вид из любого контроллера вида? Я планировал получить ссылку на AppDelegate и вызывать displayViewcontroller: с новым контроллером, который я только что создал в этом классе, но это приводит к сбою. Мне нужно сначала сохранить его в массиве, а затем отправить эту ссылку в этот метод. Это действительный подход - сделать массив viewControllers открытым, а затем вызвать этот метод с помощью lastObject или как его настроить?

+0

Быстрый вопрос. Вы работаете в Mavericks или Yosimite? – MacUserT

+0

@MacUserT Yosemite :) – Joey

ответ

1

Что интересного в вашем коде, так это то, что вы каждый раз назначаете новый контроллер просмотра каждый раз, когда вы вызываете IBAction. Может случиться так, что ваш взгляд будет совершенно новым при каждом вызове метода IBAction, но я думаю, что у вас есть только ограниченное количество просмотров, которые вы хотите показать. Насколько мне известно, это делает ваше мнение только о том, чтобы жить до тех пор, пока ваш метод IBAction длинный. То, что представление все еще существует, состоит в том, что вы его не обновили. Однако вызов метода внутри контроллера представления, который больше не находится в куче (поскольку вы оставили метод IBAction и все локальные объекты, такие как ваш контроллер представления, взяты из кучи, которая используется в ARC), это приводит к сбою приложения, поскольку вы ссылаетесь пространство памяти, которое не используется или не используется каким-либо другим.

Почему приложение работает, когда вы показываете представление в массив viewcontrollers? Я предполагаю, что этот массив является массивом, который был запущен в AppDelegate, и теперь вы добавляете контроллер представления с большим количеством ссылок на массив viewcontrollers. Когда вы покидаете метод IBAction, контроллер представления по-прежнему имеет сильную ссылку, и ARC не освобождает контроллер вида.

Правильно ли это? Ну, это работает. Я не думаю, что это считается очень хорошим программированием, поскольку вы не выделяете/не запускаете объект в методе, который должен оставаться в живых после выхода из метода. Лучше было бы распределять и инициализировать ваш контроллер (ы) просмотра где-нибудь в режиме init, awakeFromNIB или windowDidLoad вашего AppDelegate. Проблема с вашим текущим решением заключается в том, что вы создаете бесконечный массив контроллеров представлений, из которых вы используете только последний. Где-то ваша программа почувствует бремя этого чрезвычайно длинного массива довольно тяжелых объектов (контроллеров просмотра) и закончится память.

Надеюсь, это поможет.

Кстати, это не зависит от использования Маверикса или Йосемити. Я думал о решении раскадровки, но это не отвечало бы на ваш вопрос.

С наилучшими пожеланиями, MacUserT

Смежные вопросы