I’m more familiar with C++ than i am with Swift, but I’m struggling with getting the architecture right for my problem.
The App Delegate talks to my custom ‘MenuSystem’ singleton and says ‘load the app storyboard and make key&visible’ and all that good stuff.
However, the type of menu that the ‘MenuSystem’ class will use will vary by device. i.e. on iPhone - just as an example - it could be a drawer type menu, but on iPad it might be a tab bar and on macOS it might be a tool bar or side menu…
So the menu system class has a property called ‘menuController’ and there is a custom protocol that all the actual subclassed View Controllers (i.e. uitableview for drawer, uitabviewcontroller for tab bar etc etc etc)
This protocol defines all the common things that the ‘MenuSystem’ class needs to communicate to the actual, in use, menu.
The protocol is called ‘RootMenuProtocol’
Each of these will be implemented by an actual class e.g. a subclass of UITableViewController that conforms to the ‘RootMenuProtocol’ protocol.
So in the MenuSystem singleton, I need the property ‘self.menuController’ to refer to any one of the 3 possible (or more) classes that conform to the protocol.
The problem with this architecture is that when I try and then assign the type of UIViewController currently assigned to the property ‘self.menuController’ to ‘rootWindow?.rootViewController’ I get an error : Cannot assign value of type '(any RootMenuProtocol)?' to type 'UIViewController?'
Here's the code:
App Delegate
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)
}
MenuSystem Singleton
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)
}
}
MenuRootTabBarViewController
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)
{
}
}
MenuRootTableViewController
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
}
}
Can someone show me what I've misunderstood about Swift architecture and inheritance/protocols?
I just want the property 'self.menuController' to point to whichever UIViewController subclass I've got that also musts conform to the 'RootMenuProtocol'.
Aucun commentaire:
Enregistrer un commentaire