gmoraleda
gmoraleda

Reputation: 1953

MainViewController doesn't get notifications from NSNotificationCenter

My main class is an UITableViewController. I'm fetching some JSON data with a ConnectionManager class and parsing it with an ItemManager class. The communication between classes is done using the NotificationCenter. Whenever there is a response from ConnectionManagerit sends a notification to ItemManager and then it parses it.

ConnectionManager posts notifications and ItemManager receives them correctly. I want to use the same approach to update my table view. The problem is with my main class. It doesn't receive the notifications from the ItemManager when it is done parsing.

Some code:

class ConnectionManager {

  private let URL = "http://foo.json"
  private var response: Data?

  init () {
    getData()
  }

  func getData() {
    let req = NSMutableURLRequest(url: NSURL(string: URL)! as URL)
    req.httpMethod = "GET"
    URLSession.shared.dataTask(with: req as URLRequest) { data, response, error in
      if error != nil {
        //HTTP request failed
        NSLog(error?.localizedDescription ?? "Unknown Error")
        NotificationCenter.default.post(name: Notification.Name(NotificationCenterKeys.NOK), object: nil)
      } else {
        //HTTP request succeeded
        self.response = data
        NotificationCenter.default.post(name: Notification.Name(NotificationCenterKeys.OK), object: nil)
      }
      }.resume()
  }
}

class ItemManager {
  private var cm: ConnectionManager
  private var items = [Item]()

  init() {
    self.cm = ConnectionManager()
    NotificationCenter.default.addObserver(self, selector: #selector(self.parseResponse), name: Notification.Name(NotificationCenterKeys.OK), object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.noData), name: Notification.Name(NotificationCenterKeys.NOK), object: nil)
  }

  @objc private func noData() {
    NSLog("No data to parse")
  }

  @objc private func parseResponse() {
    do {
      if let data = cm.getResponse() {
        let items: NSDictionary = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
        let rawItems = items["numbers"] as! [Int]
        self.items = parseItems(rawItems: rawItems)
    NotificationCenter.default.post(name: Notification.Name(NotificationCenterKeys.PARSED), object: nil)

      }
    } catch {
      print("Error deserializing JSON: \(error)")
    }
  }

And finally my UITableViewController:

class MainViewTableViewController: UITableViewController {

  var items = [Item]()
  var dataAvailable = false
  var im = ItemManager()
  var dataLabel = "Loading Data..."

  override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateTable), name: Notification.Name(NotificationCenterKeys.PARSED), object: nil)
    setTable()
  }

  @objc func updateTable() {
    if im.getItems()?.count != 0 {
      items = im.getItems()!
      dataAvailable = true
    } else {
      dataAvailable = false
      dataLabel = "No Data Available"
    }
    self.tableView.reloadData()
  }

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

  func setTable() {
    title = "Test"
    tableView.rowHeight = 40
  }

  // MARK: - Table view data source

  override func numberOfSections(in tableView: UITableView) -> Int {
    var numOfSections = 0
    if dataAvailable {
      numOfSections = 4
      return numOfSections
    } else {
      let noDataLabel: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height))
      noDataLabel.text = dataLabel
      noDataLabel.textColor = UIColor.black
      noDataLabel.textAlignment = .center
      tableView.backgroundView = noDataLabel
      tableView.separatorStyle = .none
    }
    return numOfSections
  }

  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return getNumOfItemsPerSection(section: section)
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
    guard let sectionNumber = SectionNumber(rawValue: indexPath.section) else { return cell }
    let elements = self.items.filter({ $0.sectionNumber == sectionNumber })
    cell.nameLabel?.text = elements[indexPath.row].itemNumber?.description
    if elements[indexPath.row].checkmark {
      cell.accessoryType = .checkmark
    } else { cell.accessoryType = .none }
    return cell
  }

  func getNumOfItemsPerSection(section: Int) -> Int {
    guard let sectionNumber = SectionNumber(rawValue: section) else { return 0 }
    return self.items.filter({ $0.sectionNumber == sectionNumber }).count
  }

  override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return "Section \(section + 1)"
  }
}

Upvotes: 0

Views: 50

Answers (1)

gmoraleda
gmoraleda

Reputation: 1953

Found the problem! I'm registering the observer after receiving the notification (ups)

class MainViewTableViewController: UITableViewController {

  var items = [Item]()
  var dataAvailable = false
  var im: ItemManager? = nil

  override func viewDidLoad() {
    super.viewDidLoad()
    setTable()
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateTable),
                                           name: Notification.Name(NotificationCenterKeys.END), object: nil)
    im = ItemManager()
  }

...

Now works just fine :-)

Upvotes: 1

Related Questions