Kumar Gaurav
Kumar Gaurav

Reputation: 769

Swift: How to handle synchronisation between table view and method updating table view

I have an array in swift which is constantly being updated by another method and it also needs to be loaded to table view after update. The method updating the array is called frequently. I am having threading issue. I tried using a lock on array when the updating method is called. It did improve but but it is not working quite well as well. I am getting fatal error: Index out of range when it is updating the table in case of large number of elements (around >50) in array.

What would be the best approach to handle this situation and make it thread-safe. I am new to Swift.

Below is the function to update myArray:

func updateMyArray() {
       objc_sync_enter(self.myArray)
                //do some stuff with my Array
        //…………add some elements in array………
        //…………remove some elements in array……
                DispatchQueue.main.async {
                    self.myTable.reloadData()
                    }
       objc_sync_exit(self.myArray)

    }

Below is the table delegate methods:

func numberOfRows(in tableView: NSTableView) -> Int {
      return myArray.count
}

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        var cellText: String = myArray[row]
        if let cell = myTable.make(withIdentifier:  “myCellIdentifier", owner: nil) as? NSTableCellView {
            cell.textField?.stringValue = cellText
            return cell
        }
}

updateMyArray() is called every 10 seconds

override func viewDidAppear() {
        _ = Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(self.updateMyArray), userInfo: nil, repeats: true)
     }

updateMyArray() is called by pushing refresh button

@IBAction func refreshMyArray(_ sender:NSButton){
     self.updateMyArray()
}

Upvotes: 0

Views: 273

Answers (2)

Kumar Gaurav
Kumar Gaurav

Reputation: 769

This is what worked for me:

In updateMyArray() method:

func updateMyArray() {
        self.updatingTableData = true
        //do some stuff with my Array
        //…………add some elements in array………
        //…………remove some elements in array……     
       self.updatingTableData = false
        //following can also be done in didSet part of myArray variable
       DispatchQueue.main.async {
             self.myTable.reloadData()
       }

    }

In table view delegate method:

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        if self.updatingTableData == true || row >= self.printers.count {
                 return nil
        }
        var cellText: String = myArray[row]
        if let cell = myTable.make(withIdentifier:  “myCellIdentifier", owner: nil) as? NSTableCellView {
            cell.textField?.stringValue = cellText
            return cell
        }
}

Upvotes: 0

Jaafar Barek
Jaafar Barek

Reputation: 420

When declaring your array add this:

var myArray=[type]() {
   didSet{
       DispatchQueue.main.async {
          self.myTable.reloadData()
        }
    }
}

So whenever your array is updated the tableView is reloaded with proper data.

Upvotes: 1

Related Questions