Повторное использование UIViewController (с UITableView) для Master / Detail View Controller в приложении Master-Detail? - PullRequest
0 голосов
/ 06 января 2019

Я использую это руководство Рэя Вендерлиха в качестве руководства для проекта, над которым я работаю. Однако я пытаюсь расширить этот шаблон, чтобы включить в него подкаталоги, под-подкаталоги, под-под-подкаталоги и т. Д.

Например, если вы щелкнете по ячейке «Candy Cane» в главном / домашнем каталоге, вы попадете в «новый» контроллер представления с табличным представлением (он же экран подкаталога), который будет отображать различные продавцы леденцов и их цены на дорогие или дешевые (это будет подзаголовок для каждого ряда). См. subCategory ... текстовые файлы внизу.

Я использую слова категории и каталог взаимозаменяемо в этом сообщении.

Вот первый улов. В прошлом я создавал проект, который делает именно это, но я делал это через множество раскадровок и просматривал файлы контроллеров для каждой подкатегории, которую я тоже просматривал. Тот же принцип применяется для перехода от экранов подкатегории к экранам подкатегории и т. Д.

Я не пытаюсь рекламировать: Но, в частности, приложение, над которым я работаю, называется iEngineering и доступно бесплатно в AppStore. Пожалуйста, ознакомьтесь с библиотечной частью приложения, так как я считаю, что оно даст дополнительную помощь в понимании моей конечной цели. Имейте в виду, что текущая версия приложения была создана с использованием бесконечного количества раскадровок и файлов контроллеров, которые должны создаваться при каждом запуске симулятора в Xcode. Просмотр скриншотов приложения, которые показывают функцию библиотеки, должен быть достаточным без загрузки приложения.

Вот второй улов. У меня также есть подкатегории и так далее в этом приложении. Например, если щелкнуть ячейку на экране подкатегории, в которой показан список поставщиков и цен на конфеты, то вы перейдете на новый экран (подкатегорию) ко всем различным конфетам данного производителя. продажи. Так что в моем готовом текстовом файле ниже, subCandyCaneTextFile.txt, если вы нажмете на ячейку с надписью «Candy Cane King», вы попадете на экран, который показывает «Candy Cane King» в качестве заголовка навигации, и вы увидите / загрузить список (импортированный посредством чтения текстового файла), в котором показаны все леденцы, которые предоставляет Candy Cane King. Я не предоставил этот и другие текстовые файлы, которые я считаю подкатегориями . Я хотел бы, чтобы вы все помнили об этом, когда я задаю корень / суть моего вопроса внизу.

В этом проекте я хочу отойти от использования нескольких раскадровок со многими контроллерами представления. Это потому, что мой предыдущий проект занимал ~ 5-10 минут для компиляции / сборки каждый раз, когда я собираюсь собрать его в симуляторе. Поэтому я пытаюсь прочитать текстовый файл во время выполнения проекта для каждого нового экрана / категории в моем приложении. Я надеюсь, что это даст мне гораздо, намного быстрее время выполнения (~ 10 секунд).

В приведенном ниже примере контроллер категории / основного представления представляет свои данные, читая в текстовом файле candyTextFile.txt

МОЙ ВОПРОС: Как я могу перейти (перейти от | удаления) старых данных и (загрузить | заменить) в новые данные для экранов подкатегории? Я думал о том, чтобы попытаться сделать так, чтобы это был экран Диспетчера подробностей в учебнике Ray Wenderlich ; однако тогда я не уверен, как перейти к экрану подкатегории. Поэтому я думаю, что другой моей возможностью может быть многократное повторное использование одного контроллера представления с UITableView (Master View Controller). Я не уверен в правильном подходе к этому, поскольку я все еще относительно новичок в изучении Swift и Xcode.

Обзор текущего проекта через Xcode для этого поста.

В моем MasterViewController.swift,

    import UIKit

    class MasterViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    // MARK: - Properties
    @IBOutlet var tableView: UITableView!
    @IBOutlet var searchFooter: SearchFooter!

    var detailViewController: DetailViewController? = nil

    var candies = [Candy]()
    var filteredCandies = [Candy]()

    let searchController = UISearchController(searchResultsController: nil)

    // MARK: - View Setup
    override func viewDidLoad() {
    super.viewDidLoad()

    // Setup the Search Controller
    searchController.searchResultsUpdater = self
        searchController.obscuresBackgroundDuringPresentation = false
    searchController.searchBar.placeholder = "Search Candies"
    navigationItem.searchController = searchController
    definesPresentationContext = true

    // Setup the Scope Bar
    searchController.searchBar.scopeButtonTitles = ["All", "Chocolate","Hard", "Other"]
    searchController.searchBar.delegate = self

    // Setup the search footer
    tableView.tableFooterView = searchFooter


    setupArray()



    if let splitViewController = splitViewController {
        let controllers = splitViewController.viewControllers
        detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
    }

    }


    private func setupArray() {
        if let filepath = Bundle.main.path(forResource: "candyTextFile", ofType: "txt") {
            do {
                let contents = try String(contentsOfFile: filepath)
                let lines_separatedBy_n : [String] = contents.components(separatedBy: "\n")
                let string = lines_separatedBy_n.map { String($0) }.joined(separator: ", ")
                var lines_separatedBy_comma : [String] = string.components(separatedBy: ", ")

                // I've put this in to remove the last bit of the file that was causing the count to be one too high.
                // I'm guessing that's why you had something similar previously?
                lines_separatedBy_comma.removeLast()

                for (index, element) in lines_separatedBy_comma.enumerated() {
                    if index % 2 == 0 {
                        let newCategory = element
                        let newName = lines_separatedBy_comma[index + 1]
                        let newCandy = Candy(category: newCategory, name: newName)
                        candies.append(newCandy)
                    }
                }
                for candy in candies {
                    print("category: \(candy.category), name: \(candy.name)")
                }
                //("\ncandies: \(candies)")
            } catch let error as NSError {
                print(error.localizedDescription)
            }
        }

            print("\ncandies: \(candies)")

    }

    override func viewWillAppear(_ animated: Bool) {
    print("splitViewController!.isCollapsed: \(splitViewController!.isCollapsed)")

    if splitViewController!.isCollapsed {
      if let selectionIndexPath = tableView.indexPathForSelectedRow {
        tableView.deselectRow(at: selectionIndexPath, animated: animated)
      }
    }
    super.viewWillAppear(animated)
    }

    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    }

    // MARK: - Table View
    func numberOfSections(in tableView: UITableView) -> Int {
    return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if isFiltering() {
        print("Is filtering")
        searchFooter.setIsFilteringToShow(filteredItemCount: filteredCandies.count, of: candies.count)
        return filteredCandies.count
    }
    print("Is not filtering")
    searchFooter.setNotFiltering()
    return candies.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    let candy: Candy
    if isFiltering() {
        candy = filteredCandies[indexPath.row]
    } else {
        candy = candies[indexPath.row]
    }
    cell.textLabel!.text = candy.name
    cell.detailTextLabel!.text = candy.category
    return cell
    }

    // MARK: - Segues
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            if let indexPath = tableView.indexPathForSelectedRow {
                let candy: Candy
                if isFiltering() {
                    candy = filteredCandies[indexPath.row]
                } else {
                    candy = candies[indexPath.row]
                }
                let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
                controller.detailCandy = candy
                controller.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
                controller.navigationItem.leftItemsSupplementBackButton = true
            }
        }
    }

    func filterContentForSearchText(_ searchText: String, scope: String = "All") {


        filteredCandies = candies.filter({
            (candy : Candy) -> Bool in
        let doesCategoryMatch = (scope == "All") || (candy.category == scope)
            if searchBarIsEmpty(){
                return doesCategoryMatch
            }else {
                return doesCategoryMatch && candy.name.lowercased().contains(searchText.lowercased())

            }
        })

        tableView.reloadData()
    }


    func searchBarIsEmpty() -> Bool {
        return searchController.searchBar.text?.isEmpty ?? true
    }

    func isFiltering() -> Bool {
        let searchBarScoperIsFiltering = searchController.searchBar.selectedScopeButtonIndex != 0
        return searchController.isActive && (!searchBarIsEmpty() || searchBarScoperIsFiltering)
    }


    }

    extension MasterViewController: UISearchBarDelegate {
    // MARK: - UISearchBar Delegate
    func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
        filterContentForSearchText(searchBar.text!, scope: searchBar.scopeButtonTitles![selectedScope])
    }

    }

    extension MasterViewController: UISearchResultsUpdating {
    // MARK: - UISearchBar Delegate
    func updateSearchResults(for searchController: UISearchController) {
        let searchBar = searchController.searchBar
        let scope = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
        filterContentForSearchText(searchController.searchBar.text!, scope: scope)
    }
    }

В candyTextFile.txt,

Chocolate, Chocolate Bar
Chocolate, Chocolate Chip
Chocolate, Dark Chocolate
Hard, Lollipop
Hard, Candy Cane
Hard, Jaw Breaker
Other, Caramel
Other, Sour Chew
Other, Gummi Bear
Other, Candy Floss
Chocolate, Chocolate Coin
Chocolate, Chocolate Egg
Other, Jelly Beans
Other, Liquorice
Hard, Toffee Apple

В subCandyCaneTextFile.txt,

Cheap, Brachs
Expensive, Spangler
Expensive, Bobs
Cheap, Candy Cane King
Expensive, Jelly Belly

Другое, подкатегория, файлы:

В subDarkChocolateTextFile.txt,

Cheap, Ghirardelli
Expensive, Dove
Expensive, Lindt
Cheap, Hersheys
Expensive, Hu Dark

В subLollipopTextFile.txt,

Cheap, Zollipops
Cheap, YumEarth
Expensive, Dum Dums

Спасибо всем за потраченное время и любые советы, которые вы все сможете предложить. Я очень ценю это.

1 Ответ

0 голосов
/ 06 января 2019

Вы можете повторно использовать DetailViewController из той же раскадровки. Присвойте ему Storyboard ID, а затем вы можете создать новый экземпляр класса DetailViewController из текущего. Вы можете сохранить индекс нового VC, например, увеличивая его и используя его, например, чтобы получить имя файла следующей категории из предопределенного массива и загрузить его, например, в viewDidLoad

В DetailViewController класс:

    var index = 0;

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let st = UIStoryboard(name: "Main", bundle: nil)
        let vc = st.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
        vc.index = self.index + 1;
        self.navigationController?.pushViewController(vc, animated: true)
    }

storyboard setup

EDIT

Как использовать индекс

Объявление массива с вашими именами файлов: let files = ["file1", "file2", "file3"]

В setupArray() используйте

if let filepath = Bundle.main.path(forResource: files[index], ofType: "txt")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...