user7391376
user7391376

Reputation: 11

Using UserDefaults on an UITableView

I'm making an app which uses the Blogger API. In the first tab, I can search for posts and display their contents. Also, I can add posts to the "Favorites" section in the second tab. All is working, until I close the app. After re-launching, the Favorites section is gone. I tried to implement UserDefaults so that the Favorites section does not become empty after killing the app, but it does not work.

This is the code for the button which adds the post to Favorites:

vc.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))

func addTapped() {
    offlineTitles.append(cellText)
    titlesArray.append(cellText)
    subtitlesArray.append(cellSubtitle)
    let defaults = UserDefaults.standard
    defaults.set(titlesArray, forKey: "title")
    defaults.set(subtitlesArray, forKey: "subtitle")
    NotificationCenter.default.post(name: .reload, object: nil)
    let ac = UIAlertController(title: "Added!", message: "Post added to favorites", preferredStyle: .alert)
    ac.addAction(UIAlertAction(title: "Great!", style: .default))
    present(ac, animated: true)
}

and this for the FavoritesViewController.swift :

import UIKit

var offlineTitles = [String]()
var titlesArray = [String]()
var subtitlesArray = [String]()


extension Notification.Name {
static let reload = Notification.Name("reload")
}

class OfflineViewController: UITableViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(reloadTableData(_:)), name: .reload, object: nil)
    self.tableView.allowsMultipleSelectionDuringEditing = false
}

func reloadTableData(_ notification: Notification) {
    self.tableView.reloadData()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return titlesArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "OfflineCell", for: indexPath)
    let defaults = UserDefaults.standard
    let userDefaultsTitleArray = defaults.array(forKey: "title") as? [String] ?? [String]()
    let userDefaultsSubtitleArray = defaults.array(forKey: "subtitle") as? [String] ?? [String]()
    let title = userDefaultsTitleArray[indexPath.row]
    let subtitle = userDefaultsSubtitleArray[indexPath.row]
    cell.textLabel?.text = title
    cell.detailTextLabel?.text = subtitle
    return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let vc = FavouritesViewController()
    navigationController?.pushViewController(vc, animated: true)
}

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true
}

override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == UITableViewCellEditingStyle.delete {
        offlineTitles.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
    }
}
}

Upvotes: 0

Views: 693

Answers (1)

Rob
Rob

Reputation: 437412

It appears that you're reading user defaults in cellForRowAt. This is not only inefficient (if you had five favorites, you'd be reading it in five times), but is at the wrong time. For example, what will numberOfRowsInSection return? By the time that's called, you haven't yet read the user defaults into your arrays.

You should read user defaults into your arrays in viewDidLoad (as well as possibly in your reloadTableData, too).

Upvotes: 1

Related Questions