我对C++比Swift更熟悉,但我一直在努力让架构适合我的问题。
应用程序代表与我的自定义“MenuSystem”单例对话,并说“加载应用程序故事板并使键可见”以及所有这些好东西。
但是,“MenuSystem”类将使用的菜单类型将因设备而异。在iPhone上--仅举一个例子--它可能是一个抽屉式菜单,但在iPad上它可能是一个标签栏,在MacOS上它可能是一个工具栏或侧菜单...
因此菜单系统类有一个名为“menuController”的属性,并且有一个自定义协议,所有实际的子类视图控制器(即用于抽屉的uitableview、用于选项卡栏的uitabviewcontroller等)
该协议定义了“MenuSystem”类与实际使用的菜单进行通信所需的所有常见内容。
该协议被称为“RootMenuProtocol”
这些都将由一个实际的类来实现,例如UITableViewController的一个子类,符合“RootMenuProtocol”协议。
因此,在MenuSystem单例中,我需要属性'self.menuController'来引用符合协议的3个(或更多)类中的任何一个。
这种架构的问题是,当我尝试将当前分配给属性'self.menuController'的UIViewController类型分配给'rootWindow?.rootViewController'我得到一个错误:无法分配类型“”(任何RootMenuProtocol)的值?'以键入'UIViewController?”
代码如下:
应用程序委托
import UIKit
@main class AppDelegate: UIResponder, UIApplicationDelegate
{
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
// Override point for customization after application launch.
// Create Menu system and launch first view controller
MenuSystem.shared.loadInitialViewControllerAndMakeActiveInto(Window: window, UsingApplicationStoryboardWithName: "Main")
return true
}
}
RootMenuProtocol
import Foundation
protocol RootMenuProtocol
{
func transitionTo(StoryboardID: Any, UsingCustomAnimationTransition: Any)
}
菜单系统单例
import Foundation
import UIKit
class MenuSystem
{
static let shared: MenuSystem = MenuSystem()
private var menuController: RootMenuProtocol?
private init()
{
}
internal func loadInitialViewControllerAndMakeActiveInto(Window rootWindow: UIWindow?, UsingApplicationStoryboardWithName applicationStoryboardName: String)
{
if UIDevice.current.userInterfaceIdiom == .phone
{
self.menuController = UIStoryboard(name: "PBFMenuSystem", bundle: nil).instantiateViewController(withIdentifier: "drawerRootViewController") as? MenuRootTableViewController
rootWindow?.rootViewController = self.menuController
rootWindow?.makeKeyAndVisible()
}
else if UIDevice.current.userInterfaceIdiom == .pad
{
self.menuController = UIStoryboard(name: "PBFMenuSystem", bundle: nil).instantiateViewController(withIdentifier: "tabBarRootViewController") as? MenuRootTabBarViewController
rootWindow?.rootViewController = self.menuController
rootWindow?.makeKeyAndVisible()
}
else if UIDevice.current.userInterfaceIdiom == .mac
{
// Tool Bar here...
}
}
internal func requestTransitionTo(StoryboardID id: String, UsingCustomAnimationTransition transitionAnimation: UIViewControllerAnimatedTransitioning? = nil)
{
self.menuController?.transitionTo(StoryboardID: id, UsingCustomAnimationTransition: transitionAnimation as Any)
}
}
菜单RootTabBarViewController
import UIKit
class MenuRootTabBarViewController: UITabBarController, RootMenuProtocol
{
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func transitionTo(StoryboardID: Any, UsingCustomAnimationTransition: Any)
{
}
}
菜单RootTableViewController
import UIKit
class MenuRootTableViewController: UITableViewController, RootMenuProtocol
{
override func viewDidLoad()
{
super.viewDidLoad()
}
func transitionTo(StoryboardID: Any, UsingCustomAnimationTransition: Any)
{
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}
}
有人能告诉我我对Swift架构和继承/协议有什么误解吗?
我只想让'self.menuController'属性指向我所拥有的UIViewController子类,它也必须符合'RootMenuProtocol'。
1条答案
按热度按时间m4pnthwp1#
您会得到错误,因为
rootViewController
需要UIViewController
,但menuController
可以是符合RootMenuProtocol
的任何内容。没有任何东西说非视图控制器可以符合RootMenuProtocol
。如果你知道你只会有一个符合
RootMenuProtocol
的UIViewController
菜单控制器,那么改变:致:
这表明
menuController
必须是UIViewController
(或子类),也符合RootMenuProtocol
。现在您可以执行以下操作:
另一种选择是保持
menuController
不变,并重构以下内容:致:
这假设
MenuRootTabBarViewController
和MenuRootTableViewController
都符合RootMenuProtocol
(它们必须符合,否则您也会有其他错误)。