I'm building a project management app in Swift using Realm as a database to store my projects.
ThisWeekViewController is my initial View Controller; it incorporates a UITableView to show projects that are due this week. Using a Bar Button, the user can segue to AddProjectViewController, which, as the name suggests, is used to create new projects and save them to the realm database. AddProjectViewController is presented modally.
After entering the required project details, the user can click a save button, which saves the project to the realm database and dismisses the view, returning to ThisWeekViewController. However, I'm having trouble updating the TableView to reflect the addition of a new project.
After consulting the Realm documentation, I now understand that in Realm, it is not necessary to manually add or delete rows from my TableView after the database has changed. Instead, you should use a notification handler. However, I'm not quite sure how and where to incorporate it in order to reload my TableView after dismissing AddProjectViewController.
Calling the handler in ThisWeekViewController's ViewWillAppear method won't work as the view never actually disappears, because AddProjectViewController is presented modally.
AddProjectViewController:
class AddProjectViewController: FormViewController {
// Realm Initialization
let realm = try! Realm()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem?.isEnabled = false
form +++ Section()
<<< TextRow(){ row in
row.placeholder = "Postname"
row.tag = "ProjectName"
}.onChange({ (row) in
if row.cell.textField.hasText {
self.navigationItem.rightBarButtonItem?.isEnabled = true
} else {
self.navigationItem.rightBarButtonItem?.isEnabled = false
}
})
<<< TextAreaRow() { row in
row.placeholder = "Notizen"
row.textAreaHeight = .fixed(cellHeight: 240.0)
row.tag = "ProjectNotes"
}
form +++ Section()
<<< DateTimeInlineRow() { row in
row.title = "Fällig am"
row.value = Date(timeIntervalSinceNow: 0)
row.minuteInterval = 15
row.tag = "ProjectDueDate"
}
navigationOptions = RowNavigationOptions.Enabled.union(.StopDisabledRow)
animateScroll = true
rowKeyboardSpacing = 20
}
// MARK: - User defined functions
// If user presses the cancel button, the view is dismissed from screen.
#IBAction func cancelButtonPressed(_ sender: UIBarButtonItem) {
dismiss(animated: true) {}
}
// If user presses the save button, a new Project() item is created and saved to the Realm database.
#IBAction func saveButtonPressed(_ sender: UIBarButtonItem) {
// print(form.values())
let newProject = Project()
let titleRow: TextRow? = form.rowBy(tag: "ProjectName")
let projectName = titleRow?.value
newProject.title = projectName!
let notesRow: TextAreaRow? = form.rowBy(tag: "ProjectNotes")
let projectNotes = notesRow?.value
newProject.notes = projectNotes
let dueDateRow: DateTimeInlineRow? = form.rowBy(tag: "ProjectDueDate")
let projectDueDate = dueDateRow?.value
newProject.dueDate = projectDueDate
newProject.dateCreated = NSDate.now
print(newProject)
// Save the new Project to the realm database
do {
try self.realm.write {
realm.add(newProject)
}
}
catch {
print("Error saving item to Realm database. \(error)")
}
print(newProject)
self.dismiss(animated: true)
}
}
ThisWeekViewController:
class ThisWeekViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// MARK: - Variables
#IBOutlet weak var thisWeekTableView: UITableView!
// Realm initialization
let realm = try! Realm()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
print(Realm.Configuration.defaultConfiguration.fileURL!)
}
// MARK: - Data Source / Delegate Methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 7
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//TODO: Handle user selection of a specific planned post
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Variables
let thisWeekCell = thisWeekTableView.dequeueReusableCell(withIdentifier: ThisWeekTableViewCell.reuseIdentifier()) as! ThisWeekTableViewCell
let today = Date()
let day = Calendar.current.date(byAdding: .day, value: indexPath.row, to: today)
let dayNumber = Calendar.current.component(.day, from: day!)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
let dayName = dateFormatter.string(from: day!)
let startOfToday = Calendar.current.startOfDay(for: day!)
let endOfToday = Calendar.current.date(byAdding: .second, value: 86399, to: startOfToday)!
let projectNamesForCurrentDay = projectNamesForDay(startOfDay: startOfToday, endOfDay: endOfToday)
thisWeekCell.setupProjectNameLabel(projectNames: projectNamesForCurrentDay)
if indexPath.row == 0 {
thisWeekCell.dayNumberLabel.textColor = UIColor.orange
thisWeekCell.dayTextLabel.text = "Heute (\(dayName))"
}
if indexPath.row == 1 {
thisWeekCell.dayTextLabel.text = "Morgen (\(dayName))"
}
if indexPath.row > 1 {
thisWeekCell.dayTextLabel.text = dayName
}
thisWeekCell.dayNumberLabel.text = String(dayNumber)
return thisWeekCell
}
// MARK: - User definded functions
/**
Initial setup for the TableView. Registers all neccessary custom cells, sets the delegate and dataSource, and enables AutoLayout.
*/
func setupTableView() {
thisWeekTableView.register(UINib(nibName: ThisWeekTableViewCell.nibName(), bundle: nil), forCellReuseIdentifier: ThisWeekTableViewCell.reuseIdentifier())
thisWeekTableView.delegate = self
thisWeekTableView.dataSource = self
thisWeekTableView.rowHeight = UITableView.automaticDimension
thisWeekTableView.estimatedRowHeight = 54.0
}
/**
Takes two boundary objects of type Date and returns an array of strings containing the titles of all projects in the database that have a due date between the boundary dates.
- Parameter startOfDay: The start-of-day boundary object
- Parameter endOfDay: The end-of-day boundary object
- Returns: An array of strings containing project titles
*/
func projectNamesForDay(startOfDay: Date, endOfDay: Date) -> [String] {
let filteredProjects = realm.objects(Project.self).filter("dueDate BETWEEN %#", [startOfDay, endOfDay])
var projectNames = [String]()
for project in filteredProjects {
projectNames.append(project.title)
}
return projectNames
}
}
You should use Realm notification to auto update tableview each time Project Result change:
// Observe Realm Notifications
let token = projectResult.observe { notification, realm in
// reloadTableView
}
// later
token.invalidate()
Related
I have one date picker. It chooses the starting time and is displayed in a text field as a string. I have a table view in which each cell would show that textfield. And also I have an add button which then saves the text field's string in the realm database. Realm is used t load the tavleView. Now I want to sort the data in the realm so that it displays the cells according to the starting time that each cell has.
class NewActivityTableViewController: UITableViewController {
#IBOutlet weak var startingTimeTxt: UITextField!
let datePickerTime = UIDatePicker()
let realm = try! Realm()
override func viewDidLoad() {
super.viewDidLoad()
startingTimeTxt.delegate = self
datePickerTime.datePickerMode = .time
}
Then I connected my textView with the date picker and on pressing a toolbar done button, it got displayed as a string.
#objc func donePressed(sender: UIBarButtonItem) {
//formatter
let formatter = DateFormatter()
formatter.dateStyle = .none
formatter.timeStyle = .short
startingTimeTxt?.text = formatter.string(from: datePickerTime.date)
self.view.endEditing(true)
}
Then on pressing the add button , all of the data will get stored to the realm
#IBAction func AddButtonPressed(_ sender: UIBarButtonItem) {
let cell = ScheduleCellDetails()
cell.startingTime = startingTimeTxt.text ?? ""
saveSchedule(cell: cell)
}
func saveSchedule(cell: ScheduleCellDetails) {
do {
try realm.write {
realm.add(cell)
}
} catch {
print("Error saving category \(error)")
}
}
}
My realm data class
class ScheduleCellDetails: Object {
#objc dynamic var startingTime: String = ""
}
My code do not add values from a while statement of a UIViewController to an Array of a UITableViewController.
This is for a getter function to allow me to see all childrens values under other childrens. Now I'm going to be more specific:
My database node is made of:
Cars -> 0, 1, 2, 3, ... -> Model, Price, ... -> String
As you can see, The number of childs is undefined, so I have to use this control method:
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to cars array
}
First of all, In a loading ViewController, I get code node keys of cars and save them to cars variable of type NSMutableArray of the TableViewController. Then I will do the same thing in the TableViewController to get all indexpath.row childrens value.
let rootRef = Database.database().reference()
let carconditionalRef = rootRef.child("Cars")
carconditionalRef.observe(.value) {(snap: DataSnapshot) in
//Get all the children from snapshot you got back from Firebase
let snapshotChildren = snap.children
//Loop over all children (code) in Firebase
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to cars array
let carvc = Cars_Table();
carvc.cars.add(child.key)
}
}
It results that with this code I still have empty NSMutableArray. How can I solve this?
Edit 1
I fixed that snippet to this:
import UIKit
import FirebaseDatabase
class Loading: UIViewController {
#IBOutlet weak var loading: UIActivityIndicatorView!
var mother: NSMutableArray = []
override func viewDidLoad() {
super.viewDidLoad()
start()
}
func start() {
loading.startAnimating()
if #available(iOS 10.0, *) {
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { (timer) in
//let's dance
self.loading.startAnimating()
//call data from database
let rootRef = Database.database().reference()
let conditionalRef = rootRef.child("Cars")
conditionalRef.observe(.value) {(snap: DataSnapshot) in
// Get all the children from snapshot you got back from Firebase
let snapshotChildren = snap.children
// Loop over all children (code) in Firebase
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to cars array
self.mother.add(child.key)
}
self.move()
self.loading.stopAnimating()
self.performSegue(withIdentifier: "loadingfinish", sender: nil)
}
}
} else {
// Fallback on earlier versions
}
}
func move() {
let vc = Cars_Table()
vc.cars = self.mother
}
}
Edit 2
I tried using the recursive method, but it did not work. So I tried one more time with the iterative method this time using the while statement.
Here my new function, this time directly in the Car_TableView.swift:
func loadData() {
//call data from database
let rootRef = Database.database().reference()
let conditionalRef = rootRef.child("Cars")
conditionalRef.observe(.value) {(snap: DataSnapshot) in
// Get all the children from snapshot you got back from Firebase
let snapshotChildren = snap.children
// Loop over all children (code) in Firebase
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to cars array
self.populateTable.append(child.key)
}
var counter = 0
while counter > -self.populateTable.count {
counter -= 1
let rootRef = Database.database().reference()
let userRef = rootRef.child("Cars").child("\(self.populateTable.count+counter)")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let userDict = snapshot.value as! [String: Any]
let model1 = userDict["Model"] as! String
self.model.add(model1)
let detail1 = userDict["Detail"] as! String
self.detailpage.add(detail1)
let year1 = userDict["Year"] as! String
self.year.add(year1)
let carPrice1 = userDict["Price"] as! String
self.price.add(carPrice1)
let carimageURL1 = userDict["imageURL"] as! String
self.imagePathString.add(carimageURL1)
}) //end observeSingleEvent
}
}
}
When I go to do the while, the observeSingleEvent will be work, but it will repeat n^2 times. Why does this happen?
Edit 3
Since the problem seems to be changed since the start, I edited to give all the relevant details. So, the problem now is different and now are two:
When I load database I have n^2 repeated instruction
To see the table filled with database data, I have to touch the tab bar button to the next ViewController then touch the tab bar button to come back on Car_TableView.swift
For the first problem... onestly I have no idea why this happens 😅
For the second problem I thought to use SVProgressHUD to reload data but it doesn't work on loadData() function and if I try the Instance Method tableView.reloadData() it crashes.
variables are all NSMutableArray since that I have to load a lot of stuff that can change in the time
My viewDidLoad() function is very easy as you can see:
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
This is my Table view data source in our Car_TableView.swift:
override func numberOfSections(in tableView: UITableView) -> Int {
return populateTable.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return populateTable.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "carTableCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! Car_Cell
cell.carLabel?.text = "\(self.model[indexPath.row])"
cell.carSubtitle?.text = "Year: \(self.year[indexPath.row]) - Price: \(self.price[indexPath.row])$"
Alamofire.request("\(self.imagePathString[indexPath.row])").response { response in
guard let image = UIImage(data:response.data!) else {
// Handle error
return
}
let imageData = image.jpegData(compressionQuality: 1.0)
cell.carImage.contentMode = .scaleAspectFit
cell.carImage.image = UIImage(data : imageData!)
}
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowcarDetails" {
let myIndexPath = self.tableView.indexPathForSelectedRow!
//save detail page url in UserDefault
let SVDetail = self.detailpage[myIndexPath.row]
let SVDetaildefaults = UserDefaults.standard
SVDetaildefaults.set(SVDetail, forKey: "sv_detail")
SVDetaildefaults.synchronize()
_ = segue.destination
as! Car_Detail
}
}
//SET CELLS SIZE
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0,1,2,3,4:
return 100
default:
return 100
}
}
I also re-post the loadData() function because I simplified the operation in an only while statement:
func loadData() {
//call data from database
let rootRef = Database.database().reference()
let conditionalRef = rootRef.child("Cars")
conditionalRef.observe(.value) {(snap: DataSnapshot) in
// Get all the children from snapshot you got back from Firebase
let snapshotChildren = snap.children
// Loop over all children (code) in Firebase
while let child = snapshotChildren.nextObject() as? DataSnapshot {
// Get code node key and save it to cars array
self. populateTable.append(child.key)
let userRef = rootRef.child("Cars").child("\(child.key)")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let userDict = snapshot.value as! [String: Any]
let address1 = userDict["Address"] as! String
self.address.add(address1)
let detail1 = userDict["Detail"] as! String
self.detailpage.add(detail1)
let carnumberOfRooms1 = userDict["numberOfRooms"] as! String
self.numberOfRooms.add(carnumberOfRooms1)
let carPrice1 = userDict["Price"] as! String
self.price.add(carPrice1)
let carimageURL1 = userDict["imageURL"] as! String
self.imagePathString.add(carimageURL1)
}) //end observeSingleEvent
} //end while
} //end snap
}//end func
The problem is really, that while offline the UItableview is not populating. Basically while online it will read from a php coded website in json and parse its data to NSUserdefaults and It will display data using the defaults set. This works very well when online.
I tested it like this. first I run the code while online( wifi connected ) to first populate the defaults, then exit the tableview, turn wifi off, and then go back in. Nothing shows. I put a breakpoint/print text where the code should had run, but it breakpoint never got excuted, the print text never got printed.
is there a reason why the code isnt running when offline? am i missing a setting i should add?
var messagesArray:[String] = [String]()
var dateArray:[String] = [String]()
class Singleton {
static let sharedInstance: UserDefaults = {
let instance = UserDefaults.standard
// setup code
return instance
}()
}
//let defaults = UserDefaults.standard
let defaults = Singleton.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
//removeDefaults()
if (isInternetAvailable() == true)
{
self.retrieveMessages("")
//storeLocal()
}
else {
// TODO data is available but not displayed ??
for (key, value) in defaults.dictionaryRepresentation() {
print("\(key) = \(value) \n")
}
}
//display current notification
//nRead()
self.notificationTable.dataSource = self
self.notificationTable.delegate = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView:UITableView, numberOfRowsInSection section: Int) -> Int{
return messagesArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// this code does not run when offline
//test
let nCell = tableView.dequeueReusableCell(withIdentifier: "nCell") as UITableViewCell!
//let myLabelTitle = nCell?.viewWithTag(1) as! UILabel
let myLabelDate = nCell?.viewWithTag(2) as! UILabel
let myLabelDescription = nCell?.viewWithTag(3) as! UILabel
//messagesArray ["nContent":["Test1", "Test2"]]
myLabelDescription.text = defaults.string(forKey: "nDescription\(indexPath.row + 1)")
myLabelDate.text = defaults.string(forKey: "nDate\(indexPath.row + 1)")
//print(defaults.string(forKey:"nDate1"))
print("this code runs even while offline")
let readValue = defaults.string(forKey: "nRead\(indexPath.row + 1)")
if (readValue == "1" )
{
myLabelDate.textColor = UIColor.black
}
else
{
myLabelDate.textColor = UIColor.red
}
return nCell!
}
func tableView(_ tableView:UITableView, numberOfRowsInSection section: Int) -> Int{
return messagesArray.count
}
messagesArray.count prints 0, thus the code isn't running. fixed my own issue
I Want to display searched core data result in tableviewcontroller. i know how to display core data in tableview but i want specific data to be displayed in tableviewcontroller.
like,when user select specific city from uipickerview, then results from core data displayed in tableviewcontroller according to specific city.
some codes are listed below.
import UIKit
import CoreData
class MenuhospitalTableViewController: UITableViewController {
private var hospitalcoredata: [Hospitalcoredata] = []
var fetchResultController:NSFetchedResultsController!
override func viewDidLoad() {
super.viewDidLoad()
Load menu items from database
if let managedObjectContextt = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContextt {
let fetchRequest = NSFetchRequest(entityName: "Hospitalcoredata")
var e: NSError?
hospitalcoredata = managedObjectContextt.executeFetchRequest(fetchRequest, error: &e) as! [Hospitalcoredata]
if e != nil {
println("Failed to retrieve record: \(e!.localizedDescription)")
}
}
// Make the cell self size
self.tableView.estimatedRowHeight = 66.0
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.layoutIfNeeded()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return hospitalcoredata.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuhospitalTableViewCell
// Configure the cell...
cell.nameLabel.text = hospitalcoredata[indexPath.row].namee
cell.contactnoLabel.text = hospitalcoredata[indexPath.row].contactnoo
// cell.priceLabel.text = "$\(menuItems[indexPath.row].price as! Double)"
return cell
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/}
and code to find data from city are given below..
let entityDescription =
NSEntityDescription.entityForName("Register",
inManagedObjectContext: managedObjectContext!)
let request = NSFetchRequest()
request.entity = entityDescription
let pred = NSPredicate(format: "(name = %#)", name.text)
request.predicate = pred
var error: NSError?
var objects = managedObjectContext?.executeFetchRequest(request,
error: &error)
if let results = objects {
if results.count > 0 {
let match = results[0] as! NSManagedObject
name.text = match.valueForKey("name") as! String
contactno.text = match.valueForKey("contactno") as! String
altno.text = match.valueForKey("altno") as! String
emailid.text = match.valueForKey("emailid") as! String
textf.text = match.valueForKey("bloodgroup") as! String
textff.text = match.valueForKey("city") as! String
status.text = "Matches found: \(results.count)"
} else {
status.text = "No Match"
}
}
}
I want to mixup this two codes and display core data result accordingly "city" selection.
You should be using a NSFetchedResultsController to populate your table view. Add a dynamic predicate to its fetch request and performFetch before you update your table view.
After lots of try and help of my project guide(prof. chirag pandya),
Answer:
use preparesegue method in first view controller,
give name of push segue,
use segue name,
create predicate in second view controller and use first viewcontroller.
vary useful for searching and sorting
Code:
1)IN (firstviewcontroller)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier=="segueTest"){
var svc = segue.destinationViewController as! MenuhospitalTableViewController
svc.toPass = textff.text
}
}
2)IN (secondviewcontroller)
let pred = NSPredicate(format: "(city = %#)", toPass)
fetchRequest.predicate = pred
I working with an application that retrieves data from HealthKit and then store them in an array. What I'm trying to do is load my tableViewController with the data in that array. But unfortunately when I run the application the table appears empty.
To be more clear, I have a method that do coding to retrieve the list of required data, if fills an array (which declared at the top of the class) with these fetched data.
What I did is I called this function in the viewDidLoad function, and I printed out the array but it was empty, so I moved the call of the method to the function viewDidAppear and printed out the array. The array successfully filled with the data but I still have a problem with dynamically fill the rows with the data of this array. It still appears blank. The problem as I understood is that the table view is being loaded before the array is filled with data. I tried another solution by calling the method self.tableView.reloadData() but no luck with that.
Could anyone please give me any idea to solve this issue?
UPDATE:
Here is the viewDidLoad function:
override func viewDidLoad() {
super.viewDidLoad()
authorizeHealthKit()
updateLastGlucoRecords()
println("\(glucoReadings)")
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
And this the viewDidAppear function:
override func viewDidAppear(animated: Bool) {
updateLastGlucoRecords()
println("Hereeeee2: \(glucoReadings)")
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
Here is where the table should dynamically be loaded by the data:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
let df = NSDateFormatter()
let tf = NSDateFormatter()
df.dateFormat = "yyyy-MM-dd"
tf.dateFormat = "hh:mm:ss"
let readingDateTime = dates[indexPath.row]
let dateTabel = cell.viewWithTag(100) as! UILabel!
let timeLabel = cell.viewWithTag(101) as! UILabel!
let readingLabel = cell.viewWithTag(102) as! UILabel!
let indicator = cell.viewWithTag(103) as UIView!
dateTabel.text = df.stringFromDate(readingDateTime)
timeLabel.text = tf.stringFromDate(readingDateTime)
let reading = readings[indexPath.row]
let doubleReading = getRecordDouble(reading)
readingLabel.text = reading
let sCase = recordCase(doubleReading!)
switch (sCase) {
case "Very low": indicator.backgroundColor = UIColor.redColor()
case "Too low": indicator.backgroundColor = UIColor.orangeColor()
case "Normal": indicator.backgroundColor = UIColor.greenColor()
case "Too high": indicator.backgroundColor = UIColor.yellowColor()
case "Very High": indicator.backgroundColor = UIColor.orangeColor()
case "Danger": indicator.backgroundColor = UIColor.redColor()
default: indicator.backgroundColor = UIColor.grayColor()
}
return cell
}
And lastly here is the method that retrieves the data from HealthKit:
func updateLastGlucoRecords()
{
// 1. Construct an HKSampleType for weight
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBloodGlucose)
// 2. Call the method to read the most recent weight sample
self.healthManager.readRecent10GlucoseReadings(sampleType, completion: {(allReadings, error) -> Void in
println()
if (error != nil) {
println("Error reading glucose readings from HealthKit Store: \(error.localizedDescription)")
return;
}
var glucoseLocalizedString = self.kUnknownString;
self.glucoses = allReadings as? [HKQuantitySample]
for reading in self.glucoses! {
if let record = reading.quantity {
glucoseLocalizedString = "\(record)"
let dateTimeRecorded = reading.startDate
self.glucoReadings.append(glucoseLocalizedString)
self.glucoDates.append(dateTimeRecorded)
println("Reading: \(self.glucoReadings), Date: \(self.glucoDates)")
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
})
}
})
}
Presumably, the query you are using in HealthKit includes a completion handler. This handler is called when the query completes, and that is where you should call reloadData.
Since the HealthKit call is asynchronous, you cannot rely on the array being populated in viewWillAppear or viewDidLoad.
Try to call self.tableView.reloadData() in the main thread after your array is filled:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
And don't forget to make sure that your datasource methods are correctly implemented.