сбой при попытке сохранить значение с использованием инверсии зависимостей - PullRequest
0 голосов
/ 14 марта 2019

Я хочу реализовать инверсию зависимостей в приложении делегата в моем приложении, так как мой rootController - это мой UITabBarController, но когда я хочу попробовать это, возникает ошибка

Неустранимая ошибка: неожиданно обнаружен ноль при развертывании необязательного значения

Это мой код в моем приложенииDelagate

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()
}

На самом деле код работает, если я не использую инверсию зависимостей, как, например, мой контроллер представления обзора не использует принудительное развертывание, как это

var exploreStore = ExploreStore()

но поскольку я хочу получить знания и изучить принцип S.O.L.I.D, используя инверсию зависимостей, я хочу придерживаться этого принципа.

1 Ответ

1 голос
/ 14 марта 2019

Если я правильно понял ваш вопрос, вы хотите инициализировать свой класс в 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 и проверить правильность поведения.

EDIT

Вам необходимо обновить 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.

Вам также необходимо присвоить соответствующие идентификаторы контроллеру навигации и контроллеру панели вкладок.

Здесь - ваш демонстрационный проект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...