Home > OS >  Swift UITableView won't update with values from Healthkit
Swift UITableView won't update with values from Healthkit

Time:11-23

I've tried every method I can find resources for and I'm getting desperate. I'm trying to fill a UITableView with a users workout information. The activity name, the start date, and the duration. For some reason the UITableView refuses to get populated with this information. I thought the problem could be with the async / completion handlers so I added a button which reloads the UITableView but that doesn't work either. I know the array has values in it because the button prints them to the console successfully, but the reloadData() function still doesn't work to populate the table.

Help would be greatly appreciated as I'm not sure what else to try...

import UIKit
import HealthKit

class ViewController: UIViewController, UITableViewDataSource{
    
    /* --------Global variables for queries ------------*/
    let healthStore = HealthData.healthStore
    let workoutType = HKObjectType.workoutType()
    
    
    //Creating the table that shows activities
    @IBOutlet weak var workoutTable: UITableView!
        
        /* ---------- UI element definitions--------------- */
        
        @IBAction func checkData(_ sender: UIButton){
            print(dataValues.count) //this prints 10, which is correct
            print(dataValues) //this prints the correct values.
            DispatchQueue.main.async{
                self.workoutTable.reloadData() //this doesn't work for some reason.
            }
        }
        
        
        /*--------- Variables for the table objects --------*/
        struct workoutStruct {
            var workoutActivity: String
            var workoutDate: Date
            var workoutDuration: Double
        }
        
    var dataValues = [workoutStruct]()
        
   
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        requestAuthorization()
        async{
            let dataValues = await workoutQueryii()
            self.dataValues = dataValues
            DispatchQueue.main.async {
                self.workoutTable.reloadData()
            }
        }
    
    }
        
    //function for setting the number of rows in the UI table
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return dataValues.count
        
    }
    
    //function for mapping the data from dataValues array to the table view.
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        //use the current row as the array value
        let workout = dataValues[indexPath.row]
        
        
        //identify the cell in the table view
        let cell = workoutTable.dequeueReusableCell(withIdentifier: "workoutCell", for: indexPath) as! CustomTableViewCell
        
        cell.activityLabel.text = workout.workoutActivity
        cell.dateLabel.text = funcDateFormatter(date: workout.workoutDate)
        cell.durationLabel.text = workout.workoutDuration.formatted()
        
        return cell
    }
        
        func workoutQueryii() async -> [workoutStruct] {
            let sort = [NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)]
            //this query finds the users workout samples based on the parameters set below.
            let query = HKSampleQuery(
                sampleType: workoutType,
                predicate: nil,
                limit: 10,
                sortDescriptors: sort) { (query, resultsOrNil, error) in
                    self.dataValues = []
                    //process results
                    //create an array for the HKWorkout objects to be passed to in the query
                    var workoutsQ: [HKWorkout] = []
                    
                    if let results = resultsOrNil {
                        for result in results {
                            if let workout = result as? HKWorkout {
                                //here's a workout object
                                workoutsQ.append(workout)
                                var dataValue = workoutStruct(
                                    workoutActivity: workout.workoutActivityType.name,
                                    workoutDate: workout.startDate,
                                    workoutDuration: workout.duration )
                                
                                self.dataValues.append(dataValue)
 
                            }
                            
                        }
                        
                    }
                    
                }
            
            self.healthStore.execute(query)
            print(dataValues.count) //this returns 0
            return dataValues
            
        }
      
//End of class
}

I've tried adding async to the workoutQuery function but apparently it's being deprecated. I've tried filling the Table with an existing array of names, which works so I know the table is set up correctly. I've tried the button to reload the data, but that doesn't seem to work either.

CodePudding user response:

Well you are in an async context here. But your implementation is not correct. There is no need for the async modifier neither in the func declaration nor while calling it. You probably should take a deeper look into how swift concurrency works. Especially the older types like here with callbacks.

Nevertheless this should get you going in the meantime:

func workoutQueryii() {
    let sort = [NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)]
    //this query finds the users workout samples based on the parameters set below.
    let query = HKSampleQuery(
        sampleType: workoutType,
        predicate: nil,
        limit: 10,
        sortDescriptors: sort) { (query, resultsOrNil, error) in
            self.dataValues = []
            //process results
            //create an array for the HKWorkout objects to be passed to in the query
            //var workoutsQ: [HKWorkout] = [] // don´t know what this is for. It´s not used later on in a meaningfull manner.
            
            if let results = resultsOrNil {
                for result in results {
                    if let workout = result as? HKWorkout {
                        //here's a workout object
                        //workoutsQ.append(workout) // don´t know what this is for
                        var dataValue = workoutStruct(
                            workoutActivity: workout.workoutActivityType.name,
                            workoutDate: workout.startDate,
                            workoutDuration: workout.duration )
                        
                        self.dataValues.append(dataValue)
                        
                    }
                    
                }
            }
            
            //reload table here after appending all values to the array
            DispatchQueue.main.async {
                workoutTable.reloadData()
            }
        }
    self.healthStore.execute(query)
    // code here executes emmediatly after the query started without waiting for it to complete.
}

and the viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    
    requestAuthorization()
    workoutQueryii()
}
  • Related