Search code examples
iosswiftgrand-central-dispatch

handling errors within dispatch queue on the main thread


I've the following code, trying to wrap my head around on how can I implement GCD (I'm new) with the following background call.

Not only I have to call the findAll on the background thread but I've to populate tableview as well (delegate calls UITableViewDataSource implemented which are expecting users to be populated), so there has to be delay in population of the table view.

Please do advise if there are better methods. Is OperationQueue the answer?

override func viewWillAppear(_ animated: Bool) {
    DispatchQueue.global().async { // network call for data
        print("global")
        
        DispatchQueue.main.async { // update UI
            print("main")
        }
    }
    
    do {
        users = try model?.findAll() // data for tableView
    } catch let error as NSError {
        print("Caught NSError: \(error.localizedDescription), \(error.domain), \(error.code)")
    }
}

func fault(_ error: NSError) {
     print("Caught NSError: \(error.localizedDescription), \(error.domain), \(error.code)")

}

table view context

extension UserViewController: UITableViewDataSource {
    // number of rows
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        users?.count ?? 0
    }
    
    // cell contents
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath as IndexPath)
        cell.textLabel?.text = users?[indexPath.row].givenName
        return cell
    }
}

findAll

func findAll() throws -> [User]? {
    var statement: OpaquePointer? = nil
    let sql = "SELECT * FROM user"
    
    guard sqlite3_prepare_v2(database, sql, -1, &statement, nil) == SQLITE_OK else {
        throw NSError(domain: String(cString: sqlite3_errmsg(database)), code: 1, userInfo: nil)
    }
    
    defer { sqlite3_finalize(statement) }
    
    var users: [User] = []
    while sqlite3_step(statement) == SQLITE_ROW {
        first: String(cString: sqlite3_column_text(statement, 2)), last: String(cString: sqlite3_column_text(statement, 3))))
    }
    return users
}

Solution

  • You can show some placeholder view in the table view when you are loading data. Once data is available remove the placeholder view and update the table view with data.