2017-08-09 4 views
0

Entryというオブジェクトを持つジャーナルアプリケーションがあります。それは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) }) 
    } 
} 
+3

はStackOverflowのへようこそ、どのように[お読みくださいMinimal、Complete、Verifiableの例を作成する](https://stackoverflow.com/help/mcve)を参照してください。 –

答えて

0

あなたは、デリゲートの機能numberOfRowsInSection

試みでフィルタリングされたリストよりも大きいリストを返しますこれは、検索するときに:より安全のために

func filterContentForSearchText(searchText: String, scope: String = "All") { 
      // update the list that is a class property, you were creating a new one 

      if searchText.isEmpty { 
       filteredDreams = EntryController.shared.entries 
      } else { 
       filteredDreams = EntryController.shared.entries.filter{ $0.title.contains(searchController.searchBar.text!) } 
      }  
      tableView.reloadData() 
     } 
numberOfRowsInSectionで

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     // use the filtered list to determine count 
     return filteredDreams.count 
} 

をあなたの代わりにクラッシュの空のセルを返すことができます。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     guard indexPath.row < filteredDreams.count else { return UITableViewCell() } 
     // your code here 
    } 
+0

ありがとうございました! !!それはうまくいきましたが、テーブルビューがロードされたときに、エントリのいずれかが入力されませんでした。私は 'filteredDreams = EntryController.shared.entries'をviewDidLoadに追加して、すべてが膨れています! –

2

私は(あなたの正確な実装どおりコードを変更する)、あなたが検索コントローラがアクティブであるならば、EntryController.shared.entries.countからfilteredDreams他の戻りカウントからのカウントを返すことをここにチェックを入れなければならない

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
      return EntryController.shared.entries.count 
    } 

に問題があると思います何かのように:

if searchController.isActive && searchController.searchBar.text != "" { 
      return filterDreams.count 
    } else { 
      return EntryController.shared.entries.count 
} 
+0

あなたはまだフィルタリングされたリストより大きなリストを返していますが、テーブルはまだここでクラッシュするでしょう – Hakim

+0

私は実際の実装がユーザのために残っている間違いと論理的な解決策を指摘しました:) –

関連する問題