Как получить главное окно (делегат приложения) из другого класса (подкласс NSViewController)?

#objective-c #macos #cocoa

#objective-c #macos #какао

Вопрос:

Я пытаюсь изменить содержимое моего Windows из другого класса, то есть подкласса NSViewController.Я пытаюсь использовать приведенный ниже код, но он ничего не делает.

 [NSApplication sharedApplication]mainWindow]setContentView:[self view]]; //code in NSViewController

[NSApplication sharedApplication]mainWindow] // returns null
  

Я попытался добавить

 [window makeMainWindow];
  

в классе делегата приложения, но это не поможет.

Я что-то пропустил?

PS Также я использую приведенный ниже код для вызова любой функции делегирования в моем классе,

  [(appDelegate *) [[NSApplication sharedApplication]delegate]MyMethod];
  

но мне интересно, есть ли что-то лучше, без импорта класса делегата. Что-то вроде этого

 [[NSApplication sharedApplication]delegate]MyMethod];
  

(выдает предупреждение)

Ответ №1:

Для метода MainWindow в документах говорится:

Этот метод может возвращать значение nil, если загрузка файла nib приложения не завершена, если приемник не активен или если приложение скрыто.

Я только что создал быстрое тестовое приложение и разместил следующий код:

 NSLog(@"%@", [[NSApplication sharedApplication] mainWindow]);
  

в мой applicationDidFinishLaunching:aNotification метод и в метод действия, который я подключил к кнопке в главном окне моего приложения.

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

NSApplication предоставляет другие методы, которые могут быть вам полезны:

  • - windows — массив всех окон;
  • – keyWindow — выдает окно, которое получает ввод с клавиатуры (или ноль);
  • – windowWithWindowNumber: — возвращает окно, соответствующее номеру окна — если вы знаете номер окна, содержимое которого вы хотите заменить, вы можете использовать это;
  • – makeWindowsPerform:inOrder: — отправляет сообщение в каждое окно — вы можете использовать это для проверки каждого окна, чтобы узнать, интересует ли оно вас.

Что касается вызова методов на delegate , то то, что вы говорите, выдает предупреждение, для меня работает нормально. Например, это работает без предупреждений:

 NSLog(@"%@", [[[NSApplication sharedApplication]delegate] description]);
  

Какое именно предупреждение вы получаете? Вы пытаетесь вызвать метод, который не существует?

Комментарии:

1. Большое спасибо. У меня только одно окно. Поэтому, вероятно, я буду использовать windows, чтобы попасть в массив, и буду использовать первый объект в массиве. Что касается методов делегата, вы пробовали его из другого класса, такого как viewcontroller? когда я вызываю его, он работает нормально, но выдает предупреждение, что делегат может не реагировать на этот метод.

2. Я понимаю, что вы имеете в виду сейчас о вызовах делегата. К сожалению, сообщение [[NSApplication sharedApplication] delegate] всегда будет возвращать объект типа NSApplicationDelegate . Вам нужно будет передать его своему делегату приложения, если вы хотите отправлять ему сообщения, специфичные для вашего делегата приложения. Возможно, вы захотите задать это как отдельный вопрос?

3. Я думаю, что единственный способ сделать это — передать NSApplicationDelegate определенному делегату и импортировать его в класс. Спасибо.

4. Есть еще один способ! вы можете [[NSApplication sharedApplication]делегировать]performSelector:@selector (selectorName)]; Если вы знаете имя селектора в своем делегате, нет необходимости включать заголовок appdelegate и приведение типов. Это будет работать.

5. Как насчет в Swift Playground? Как я могу получить ненулевое MainWindow?

Ответ №2:

Борьба с macOS только что поняла это.

Цитата Apple:

MainWindow

Свойство

Главное окно приложения. (только для чтения)

Обсуждение

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

Если в вашем приложении только одно окно (которое является наиболее часто используемым случаем), используйте следующий код:

 NSWindow *mainWindow = [[[NSApplication sharedApplication] windows] objectAtIndex:0];
  

Обещайте, что это не будет равно нулю, если приложение имеет windows.

Комментарии:

1. Я комментирую вопрос 3-летней давности, но, похоже, это тоже не работает. Разве это не должно что-то возвращать, поскольку ViewController, в который входит код, загружается к моменту, когда он пытается получить окно?

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

3. Спасибо за ответ. Это один из методов TableView, поскольку он является делегатом NSTableView. Так что я не знаю, почему это не сработает, с окном, отображающим содержимое.

4. Я почти уверен, что вы не можете обещать, что оно не будет равным нулю.

5. Конечно, оно будет равно нулю , если в приложении нет окна … отредактировал ответ соответствующим образом.

Ответ №3:

Быстрые подходы для получения главного окна (если есть)

Главное окно приложения

 guard let window = NSApplication.shared.mainWindow,
else {
    // handle no main window present
}
// ... access window here
  

Массив окон приложения

 let windowArray: [NSWindow] = NSApplication.shared.windows
guard windowArray.count > 0 else {
    // hand case where no windows are present
}
let window = windowArray[0]
// ... access window here
  

Ответ №4:

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

 [myObject performSelector:@selector(theSelector) withObject:nil afterDelay:0.1];