ios - Today extension: syncing data with container app -


context

i've been playing around today extensions using this example project.

the app quite simple:

  • in containing app, have list of todo items, can mark completed
  • in today widget, see same list, can switch between completed, , incomplete items using segmented control.

my goal following: whenever there data change, either in container app, or widget, want both reflect changes:

  • if mark item completed in container app, pull down notification center, widget should updated
  • when same in widget, return app, app's state should updated

the implementation

i understand, container app, , extension run in separate processes, means 2 constraints:

  • nsuserdefaultsdidchangenotification useless.
  • managing model instances in memory useless.

i know, in order access shared container, both targets must opt-in app groups entitlements under same group id.

the data access managed embedded framework, todokit. instead of keeping properties in memory, goes straight nsuserdefaults appropriate values:

public struct shoppingitemstore: shoppingstoretype {      private let defaultitems = [         shoppingitem(name: "coffee"),         shoppingitem(name: "banana"),     ]      private let defaults = nsuserdefaults(suitename: appgroupid)      public init() {}      public func items() -> [shoppingitem] {         if let loaded = loaditems() {             return loaded         } else {             return defaultitems         }     }      public func toggleitem(item: shoppingitem) {          let initial = items()          let updated = initial.map { original -> shoppingitem in             return original == item ?                 shoppingitem(name: original.name, status: !original.status) : original         }          saveitems(updated)     }      private func saveitems(items: [shoppingitem]) {          let boxeditems = items.map { item -> [string : bool] in             return [item.name : item.status]         }          defaults?.setvalue(boxeditems, forkey: saveddatakey)         defaults?.synchronize()     }      private func loaditems() -> [shoppingitem]? {          if let loaded = defaults?.valueforkey(saveddatakey) as? [[string : bool]] {              let unboxed = loaded.map { dict -> shoppingitem in                  return shoppingitem(name: dict.keys.first!, status: dict.values.first!)             }              return unboxed         }          return nil     } } 

the problem

here's works:

  • when modify list in main app, stop simulator, , launch today target xcode, reflects correct state. true vice-versa.

this verifies, app group set correctly.

however, when change in main app, pull down notification center, out of sync. , part, don't understand.

my views data straight shared container. whenever change happens, update data in shared container.

what missing? how can sync these 2 properly? data access class not managint any state, yet don't understand why doesn't behave correctly.

additional info

  • i know mmwormhole. unfortunately not option me, since need reach proper functionality without including third party solutions.

  • this terrific article, covers topic, , might possible, need employ nsfilepresenter, although seems cumbersome, , don't understand mechanism yet. hope, there easier solution, one.

well, have learned 2 things here:

first of all, always double check entitlements, mine somehow got messed up, , that's why shared container behaved awkwardly.

second: although viewwillappear(_:) not called, when dismiss notification center, it's still possible trigger update app delegate:

func applicationdidbecomeactive(application: uiapplication) {     nsnotificationcenter.defaultcenter().postnotificationname(updatedatanotification, object: nil) } 

then in view controller:

override func viewwillappear(animated: bool) {     super.viewwillappear(animated)      nsnotificationcenter.defaultcenter().addobserverforname(updatedatanotification, object: nil, queue: nsoperationqueue.mainqueue()) { (_) -> void in         self.tableview.reloaddata()     } }  override func viewdiddisappear(animated: bool) {     super.viewdiddisappear(animated)     nsnotificationcenter.defaultcenter().removeobserver(self) } 

updating today widget simple: each time notification center pulled down, viewwillappear(:_) called, can query new data there.

i'll update example project on github shortly.


Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -