我有一個日誌應用程序,其名稱爲Entry
。它有自己的Swift文件,名爲Entry.swift
,這些日記條目使用字典數組保存。嘗試過濾字典時出現問題 - 索引超出範圍錯誤
我在UITableViewController
上添加了一個搜索欄,每當我輸入一個字母后,應用程序在調用tableView.reloadData()
後崩潰。我認爲這與過濾器錯誤地返回名爲entries
的字典數組有關,並且在調用tableView.reloadData()
時,dequeueReusableCell
上的兩個標籤都無法填充,因爲信息在字典數組中的格式不正確。
Entry.swift
//
// Entry.swift
// Journal
//
// Created by handje on 6/17/17.
// Copyright © 2017 Rob Hand. All rights reserved.
//
import Foundation
class Entry {
static fileprivate let titleKey = "title"
static fileprivate let bodyTextKey = "bodyText"
static fileprivate let dateKey = "date"
var title: String
var bodyText: String
var date: String
init(title: String, bodyText: String, date: String) {
self.title = title
self.bodyText = bodyText
self.date = date
}
func dictionaryRepresentation() -> [String: Any] {
return [Entry.titleKey: title, Entry.bodyTextKey: bodyText, Entry.dateKey: date]
}
convenience init?(dictionary: [String: Any]) {
guard let title = dictionary[Entry.titleKey] as? String,
let bodyText = dictionary[Entry.bodyTextKey] as? String, let date = dictionary[Entry.dateKey] as? String else { return nil
}
self.init(title: title, bodyText: bodyText, date: date)
}
}
extension Entry: Equatable {
static func == (lhs:Entry, rhs:Entry) -> Bool {
return
lhs.title == rhs.title &&
lhs.bodyText == rhs.bodyText
}
}
EntryListTableViewController.swift
//
// EntryListTableViewController.swift
// Journal
//
// Created by handje on 6/17/17.
// Copyright © 2017 Rob Hand. All rights reserved.
//
import UIKit
class EntryListTableViewCell: UITableViewCell {
@IBOutlet weak var dreamTitle: UILabel!
@IBOutlet weak var dreamDate: UILabel!
}
extension EntryListTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
}
class EntryListTableViewController: UITableViewController {
@IBOutlet weak var searchBar: UISearchBar!
var dreamTitle: UILabel!
let searchController = UISearchController(searchResultsController: nil)
let dreams = EntryController.shared.entries
var filteredDreams = [Entry]()
func filterContentForSearchText(searchText: String, scope: String = "All") {
let filteredDreams = EntryController.shared.entries.filter{ $0.title.contains(searchController.searchBar.text!) }
tableView.reloadData()
print(filteredDreams)
}
override func viewDidLoad() {
//cell setup
super.viewDidLoad()
let backgroundImage = UIImage(named: "DreamPageLucidity.jpg")
let imageView = UIImageView(image: backgroundImage)
imageView.contentMode = .scaleAspectFill
self.tableView.backgroundView = imageView
tableView.separatorInset = .zero
tableView.separatorColor = UIColor.lightGray
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return EntryController.shared.entries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "entryCell", for: indexPath) as! EntryListTableViewCell
let entry: Entry
if searchController.isActive && searchController.searchBar.text != "" {
entry = filteredDreams[indexPath.row] /////////ERROR HERE///////
} else {
entry = EntryController.shared.entries[indexPath.row]
}
cell.dreamTitle.text = entry.title
cell.dreamDate.text = entry.date
if cell.dreamTitle.text == "" {
cell.dreamTitle.text = "Untitled Dream"
}
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let entry = EntryController.shared.entries[indexPath.row]
EntryController.shared.deleteEntry(entry: entry)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailVC = segue.destination as? EntryDetailViewController
guard let indexPath = tableView.indexPathForSelectedRow else { return }
let entry = EntryController.shared.entries[indexPath.row]
detailVC?.entry = entry
}
}
EntryContoller.swift
//
// EntryController.swift
// Journal
//
// Created by handje on 6/17/17.
// Copyright © 2017 Rob Hand. All rights reserved.
//
import Foundation
class EntryController {
var entries = [Entry]()
static fileprivate let entriesKey = "entriesKey"
static let shared = EntryController()
init() {
load()
}
// MARK: - CRUD
func addNewEntryWith(title: String, bodyText: String, date: String) {
let entry = Entry(title: title, bodyText: bodyText, date: date)
entries.append(entry)
save()
}
func updateEntry(entry: Entry, title: String, bodyText: String, date: String) {
entry.title = title
entry.bodyText = bodyText
save()
}
// Set up search bar
func deleteEntry(entry: Entry) {
guard let index = entries.index(of: entry) else { return }
entries.remove(at: index)
save()
}
// MARK: - save/load UserDefaults
private func save() {
let entryDictionaries = entries.map {$0.dictionaryRepresentation()}
UserDefaults.standard.set(entryDictionaries, forKey: EntryController.entriesKey)
}
private func load() {
guard let entryDictionaries = UserDefaults.standard.object(forKey: EntryController.entriesKey) as? [[String: Any]] else { return }
entries = entryDictionaries.flatMap ({ Entry(dictionary: $0) })
}
}
歡迎#1,請閱讀[如何創建一個最小化,完整和可驗證的示例](https://stackoverflow.com/help/mcve)。 –