Я использую это руководство Рэя Вендерлиха в качестве руководства для проекта, над которым я работаю. Однако я пытаюсь расширить этот шаблон, чтобы включить в него подкаталоги, под-подкаталоги, под-под-подкаталоги и т. Д.
Например, если вы щелкнете по ячейке «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
Спасибо всем за потраченное время и любые советы, которые вы все сможете предложить. Я очень ценю это.