Начиная с iOS 13, UIApplication
имеет свойство connectedScenes
, равное Set<UIScene>
. У каждой из этих сцен есть delegate
, который равен UISceneDelegate
. Таким образом, вы могли получить доступ ко всем делегатам.
Сцена может управлять одним или несколькими окнами (UIWindow
), и вы можете получить UIScene
окна из его свойства windowScene
.
Если вам нужен делегат сцены для определенного контроллера представления, обратите внимание на следующее. Из UIViewController
вы можете получить его окно из вида. Из окна вы можете получить его сцену и, конечно, из сцены вы можете получить ее делегата.
Короче говоря, с помощью контроллера представления вы можете:
let mySceneDelegate = self.view.window.windowScene.delegate
Однако во многих случаях контроллер представления не имеет окна. Это происходит, когда контроллер представления представляет другой контроллер полноэкранного представления. Это может произойти, когда контроллер представления находится в контроллере навигации, а контроллер представления не является верхним, видимым контроллером представления.
Это требует другого подхода к поиску сцены контроллера представления. В конечном итоге вам нужно использовать комбинацию обхода цепочки респондентов и иерархии контроллеров представления, пока вы не найдете путь, ведущий к сцене.
Следующее расширение (может) предоставить вам UIScene из представления или контроллера представления. Когда у вас есть сцена, вы можете получить доступ к ее делегату.
Добавьте UIResponder + Scene.swift:
import UIKit
@available(iOS 13.0, *)
extension UIResponder {
@objc var scene: UIScene? {
return nil
}
}
@available(iOS 13.0, *)
extension UIScene {
@objc override var scene: UIScene? {
return self
}
}
@available(iOS 13.0, *)
extension UIView {
@objc override var scene: UIScene? {
if let window = self.window {
return window.windowScene
} else {
return self.next?.scene
}
}
}
@available(iOS 13.0, *)
extension UIViewController {
@objc override var scene: UIScene? {
// Try walking the responder chain
var res = self.next?.scene
if (res == nil) {
// That didn't work. Try asking my parent view controller
res = self.parent?.scene
}
if (res == nil) {
// That didn't work. Try asking my presenting view controller
res = self.presentingViewController?.scene
}
return res
}
}
Его можно вызвать из любого представления или контроллера представления, чтобы получить его сцену. Но обратите внимание, что вы можете получить сцену из контроллера представления только после того, как viewDidAppear
был вызван хотя бы один раз. Если вы попробуете раньше, тогда контроллер представления может еще не быть частью иерархии контроллеров представления.
Это будет работать, даже если окно представления контроллера представления равно нулю, пока контроллер представления является частью иерархии контроллеров представления и где-то выше по этой иерархии он прикреплен к окну.
Вот реализация расширения UIResponder на Objective-C:
UIResponder + Scene.h:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIResponder (Scene)
@property (nonatomic, readonly, nullable) UIScene *scene API_AVAILABLE(ios(13.0));
@end
NS_ASSUME_NONNULL_END
UIResponder + Scene.m:
#import "ViewController+Scene.h"
@implementation UIResponder (Scene)
- (UIScene *)scene {
return nil;
}
@end
@implementation UIScene (Scene)
- (UIScene *)scene {
return self;
}
@end
@implementation UIView (Scene)
- (UIScene *)scene {
if (self.window) {
return self.window.windowScene;
} else {
return self.nextResponder.scene;
}
}
@end
@implementation UIViewController (Scene)
- (UIScene *)scene {
UIScene *res = self.nextResponder.scene;
if (!res) {
res = self.parentViewController.scene;
}
if (!res) {
res = self.presentingViewController.scene;
}
return res;
}
@end
person
rmaddy
schedule
13.06.2019