Почему класс UIWindowSceneDelegate по умолчанию наследуется от UIResponder? - PullRequest
3 голосов
/ 13 февраля 2020

В iOS 13 объект UIWindowSceneDelegate не входит в цепочку респондента (я подтвердил это, напечатав цепочку респондента). Но код шаблона, который Xcode предоставляет, делает делегат класса сцены наследованным от UIResponder. Если я сделаю так, чтобы класс делегата сцены наследовал от NSObject, код все равно компилируется и запускается без проблем.

Так какой смысл в том, чтобы класс делегата сцены соответствовал UIResponder?

1 Ответ

1 голос
/ 21 февраля 2020

Я тоже это заметил, когда имел проблемы с действиями NSToolbarItem и после исследования с Бункер Я выяснил причину, хотя UIWindow s nextResponder равно UIWindowScene, он не имеет nextResponder переопределяет, что пересылает его делегату (наш класс SceneDelegate, который соответствует UIWindowSceneDelegate), это суперкласс - UIScene следующий - UIApplication, который имеет следующий делегат приложения.

Я предполагаю, что класс, соответствующий делегату сцены, должен иметь в качестве следующего респондента синтаксически сложное приложение, и даже если это достигается в Obj C, это, вероятно, еще сложнее или невозможнее в Swift. Возможно, Apple просто решила, что это не стоит хлопот. С Catalyst любой NSToolbarItem для панели инструментов оконной сцены может просто иметь свою цель, установленную на себя - делегат сцены, вместо поиска в цепочке респондента, даже у системных элементов их цель может быть изменена во время toolbarWillAddItem, как в образец . Было бы неплохо, если бы они хотя бы где-то задокументировали предупреждение о том, что делегат сцены окна не входит в цепочку респондента, особенно потому, что, как вы говорите, это подкласс UIResponder.

Если вы хотел бы , чтобы он был в цепочке, тогда я создал обходной путь (см. Код ниже). Сначала создайте подкласс UIWindowScene с методом nextResponder, возвращающим self.delegate. Во-вторых, в делегат сцены добавьте nextResponder, который возвращает UIApplication.sharedApplication (который будет перенаправлять делегату приложения). Наконец, в манифесте сцены (в Info.plist) добавьте строку в конфигурации по умолчанию, выберите в раскрывающемся списке имя класса и введите имя своего подкласса.

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

MyWindowScene.h

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyWindowScene : UIWindowScene

@end

NS_ASSUME_NONNULL_END

MyWindowScene.m

#import "MyWindowScene.h"

@implementation MyWindowScene

- (UIResponder *)nextResponder{
    return self.delegate;
}

@end

SceneDelegate.m

@implementation SceneDelegate
...
- (UIResponder *)nextResponder{
    return UIApplication.sharedApplication;
}

Scene Manfiest showing Class Name

...