我想在我的应用程序中的应用程序委托中实现依赖关系倒置,因为我的rootController
是我的UITabBarController
,但是当我尝试尝试时出现错误
致命错误:解开可选值时意外发现nil
这是我在我的appDelagate中的代码
let exploreStore = ExploreStore()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let rootController = (window?.rootViewController as? UITabBarController)?.children.first as? ExploreViewController
// Inject Data
rootController?.exploreStore = exploreStore
return true
}
这是我的探索课
class ExploreStore {
fileprivate var allItems = [ExploreItem]()
func fetch() {
for data in loadData() {
allItems.append(ExploreItem(dict: data))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [[String: AnyObject]] {
guard
let path = Bundle.main.path(forResource: "ExploreData", ofType: "plist"),
let items = NSArray(contentsOfFile: path)
else { return [[:]] }
return items as! [[String: AnyObject]]
}
}
这是我的exlporeViewController
var exploreStore: ExploreStore!
override func viewDidLoad() {
super.viewDidLoad()
// This is where the error found nil
exploreStore.fetch()
}
实际上,如果我不使用依赖关系反转,代码就可以工作,例如我的explorer视图控制器不使用像这样的强制展开
var exploreStore = ExploreStore()
但是由于我想学习知识并使用依赖倒置学习S.O.L.I.D原理,因此我要坚持这一原理。
答案 0 :(得分:1)
如果我正确理解了您的问题,则希望在AppDelegate
类中初始化您的课程,然后将其传递给UITabBarController
的第一个children
,因此您需要对您的didFinishLaunchingWithOptions
方法进行一些修改,如下所示:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "tabBar")
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
let myTabBar = self.window?.rootViewController as! UITabBarController
let firstViewController = myTabBar.children.first as? FirstViewController
firstViewController?.exploreStore = exploreStore
self.window?.makeKeyAndVisible()
return true
}
在这里我做了一些修改,因为我正在从Info.plist
检索Bundle
,而您的ExploreStore
看起来像:
class ExploreStore {
var allItems = [ExploreItem]()
func fetch() {
if let dataObjectFromPlist = loadData() {
allItems.append(ExploreItem(dict: dataObjectFromPlist))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [String: AnyObject]? {
var resourceFileDictionary: [String: AnyObject]?
if let path = Bundle.main.path(forResource: "Info", ofType: "plist") {
if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
resourceFileDictionary = dict
}
}
return resourceFileDictionary
}
}
然后在我的FirstViewController
中,可以使用
ExploreStore
类中获取数据。
exploreStore.fetch()
我的UIViewController
代码是
class FirstViewController: UIViewController {
var exploreStore: ExploreStore!
override func viewDidLoad() {
super.viewDidLoad()
exploreStore.fetch()
print(exploreStore.allItems[0].data)
}
}
这里exploreStore.allItems[0].data
将打印我的整个info.plist
文件。
您可以通过THIS演示项目自行尝试,并检查其是否正确。
编辑
您需要像这样更新didFinishLaunchingWithOptions
方法:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setupDefaultColors()
let exploreStoryBoard = UIStoryboard(name: "Explore", bundle:nil)
let navigationController = exploreStoryBoard.instantiateViewController(withIdentifier: "ExploreViewControllerNavigation") as! UINavigationController
if let exploreViewController = navigationController.children.first as? ExploreViewController {
exploreViewController.store = ExploreStore()
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = exploreViewController
self.window?.makeKeyAndVisible()
}
return true
}
您还需要更新ExploreStore
类,如下所示:
class ExploreStore {
var allItems = [ExploreItem]()
func fetch() {
if let dataObjectFromPlist = loadData() {
allItems.append(ExploreItem(dict: dataObjectFromPlist))
}
}
func numberOfItem() -> Int {
return allItems.count
}
func explore(at index: IndexPath) -> ExploreItem {
return allItems[index.item]
}
fileprivate func loadData() -> [String: AnyObject]? {
var resourceFileDictionary: [String: AnyObject]?
if let path = Bundle.main.path(forResource: "ExploreData", ofType: "plist") {
if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
resourceFileDictionary = dict
}
}
return resourceFileDictionary
}
}
因为从plist
您将获得Dictionary<String, AnyObject>
类型的对象。
您仍然不会从plist
文件中获取数据,因为它已添加到子文件夹中。因此,您首先需要为plist
找到正确的路径。
您还需要为导航控制器和标签栏控制器分配各自的标识符。
Here是您的演示项目。