1

I am playing around with WatchKit and CoreData and the demo app I wrote is working but sometimes gives unexpected results. Basically, it's a toDo app. You enter the toDo items on the iPhone and it stores them using CoreData in an entity called ToDoItem with 2 attributes: name (string) and completed (boolean). The name of items entered on the iPhone are assigned item.completed = false in the CoreData entity.

On the Apple Watch it queries CoreData on the iPhone and lists the names of the items that are not completed (item.completed == 0) in a WatchKit table view. When an item on the watch is selected the font changes to red, the row is deleted from the table, and it changes the completed value in CoreData to true (item.completed = true). The next time the Watch app is launched, the completed items no longer are listed in the table.

This works fine most of the time, but sometimes when an item is selected on the watch, it does not update CoreData with the item as item.completed = true. And once this happens, it no longer updates the items in CoreData when selected. No errors are given. If I reset the simulator, it starts working again but after a while does the same thing.

My code is below:

class InterfaceController: WKInterfaceController { @IBOutlet var table: WKInterfaceTable! override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) // Configure interface objects here. var context = CoreDataStack.sharedInstance.managedObjectContext! let request = NSFetchRequest(entityName: "ToDoItem") //CoreData entity ToDoItem contains two attributes - name (string) and completed (boolean) let fetchItems: Array = context.executeFetchRequest(request, error: nil) as! [ToDoItem] //fetches the items in the entity var counter = 0 for element in fetchItems{ counter++ println("The item name is \(element.name) and completed is \(element.completed)") //prints the items to the console } self.table.setNumberOfRows(fetchItems.count, withRowType: "ToDoRow") var theCount = 0 for element in fetchItems { if element.completed == 0 { let row = self.table.rowControllerAtIndex(theCount) as? ToDoTableRowController row?.nameLabel.setText(element.name) //populates the table with names of items that are not completed theCount++ } } } override func table(table: WKInterfaceTable, didSelectRowAtIndex rowIndex: Int) { //self.pushControllerWithName("ToDoDetail", context: nil) let row = table.rowControllerAtIndex(rowIndex) as! ToDoTableRowController row.nameLabel.setTextColor(UIColor.redColor()) //change the color of font to red when row is selected var myIndex = NSIndexSet(index: rowIndex) self.table.removeRowsAtIndexes(myIndex) //removes selected row from table var context = CoreDataStack.sharedInstance.managedObjectContext! let request = NSFetchRequest(entityName: "ToDoItem") let items = context.executeFetchRequest(request, error: nil) as! [ToDoItem] let item = items[rowIndex] item.setValue(true, forKey: "completed") //changes the selected item to completed and saves it in coredata //item.completed = true var error: NSError? if !context.save(&error) { println("Cannot save due to \(error) \(error?.localizedDescription)") } } 
2
  • Have you inspected the error returned by 'save' ? Commented Apr 21, 2015 at 10:43
  • I created breakpoints at the key points - item.setvalue and context.save, but all shows fine. I don't know if it's a bug in the watchKit simulator, and cannot test with an Apple Watch device since I don't have one as yet. I saw an article that may help. If I find the answer to this issue, I'll update this post. Commented Apr 21, 2015 at 12:54

1 Answer 1

1

How are you coordinating data between the host app and the watch extension? I'm using a Core Data store in the app group container and I found that the watch, the today widget, and the host app didn't get updates to managed objects until a save forced a merge to happen. (The managed object context doesn't notice the objects in the store have changed.) So it might be that the watch's context has the completed item but the host app still has an uncompleted item in the context.

The fix for me was to use MMWormhole so all three binaries can update each other when they touch a NSManagedObject subclass. I pass the object ID in the message and when a binary receives the message a call to context.refreshObject(managedObject, mergeChanges: true) gets everyone back in sync.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.