Search code examples
swiftuitableviewfirebasefirebase-realtime-databasekey-value-coding

iOS Populate Table View With Firebase Data Using MVC Pattern


In my Firebase project I'm trying to apply Model View Controller pattern, so I separated the controller and the class that handles firebase requests. I get this exception

exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber length]: unrecognized selector sent to instance

I'm trying to get news items from the database. Here is the model

class NewsItem: NSObject{
    var title: String?
    var detail: String?
    var photoUrl: String?
    var timestamp: String?
}

Here is the firebase handler class

protocol NewsController: class {
    func fetchedNews(_ newsItem: NewsItem)
}

class FirebaseHandler {

    private static let _instance = FirebaseHandler()

    static var Instance: FirebaseHandler{
        return _instance
    }

    weak var newsControllerDelegate: NewsController?

    func fetchNews() {
        References.Instance.newsRef.observe(.childAdded) { 
            (snapshot: DataSnapshot) in
            if let child = snapshot.value as? [String: AnyObject]{
                let newsItem = NewsItem()
                print("CHILD: \n\n\n\n\(child)\n\n\n")
                newsItem.setValuesForKeys(child)
                DispatchQueue.main.async {
                    self.newsControllerDelegate?.fetchedNews(newsItem)
                }
            }
        }
    }
}

I can get the child values printed fine, but the problem is when I call the protocol delegate method.

Here are some portions of the table view controller class where I adopt the NewsController protocol:

FirebaseHandler.Instance.newsControllerDelegate = self
FirebaseHandler.Instance.fetchNews()

Then I implement the method:

func fetchedNews(_ newsItem: NewsItem) {
    print("Item:\n\n\n\(newsItem)\n\n\n")
    self.newsItems.append(newsItem)
    self.tableView.reloadData()
}

The newsItem isn't printed since the error occurs before this method is called I guess. Any suggestions are appreciated.


Solution

  • From the reported NSNumber related error, I would guess your timestamp property is actually stored as an integer in Firebase (and not as a string). If this is the case, try changing it to:

    var timestamp: Int = 0
    

    To understand why we can't use Int? (or even Int!) above please see this answer as well.

    Also: you don't need that DispatchQueue.main.async wrapper in your observer code. All database callbacks are already called on the main thread by Firebase ;)