Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect changes in NSUserDefaults with suiteName

In my project i use app group to transfer data to apple watch! This look like this

let sharedDefaults = NSUserDefaults(suiteName: "group.com.myappname.defaults")
sharedDefaults?.setObject(MyData, forKey: "DataKey")
sharedDefaults?.synchronize()

In WKInterfaceController i getting my data with this code:

let sharedDefaults = NSUserDefaults(suiteName: "group.com.myappname.defaults")
let MyData = sharedDefaults?.objectForKey("DataKey") as! [[AnyObject]]

All work fine!

Now i try to detect if data in sharedDefaults?.objectForKey("DataKey") did changed. I try to use addObserver method:

override func willActivate() {
NSUserDefaults(suiteName: "group.com.myappname.defaults")!.addObserver(self, forKeyPath: "DataKey", options: NSKeyValueObservingOptions.New, context: nil)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>){
      print("Data Changed")
}

But "override func observeValueForKeyPath" calling only when WKInterfaceController will Activate and didn't calling when i change Data in NSUserDefaults(suiteName: "group.com.myappname.defaults")

Also i try to use NSNotificationCenter:

override func willActivate() {
let sharedDefaults = NSUserDefaults(suiteName: "group.com.myappname.defaults")
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(userDefaultsDidChangeNotificationMethod(_:)), name: NSUserDefaultsDidChangeNotification, object: nil)
}

func userDefaultsDidChangeNotificationMethod(notification: NSNotification){
 print("Data Changed")
}

It doesn't work(

What i doing wrong? How to detect if data changed?

like image 623
Dmitry Avatar asked Jul 26 '16 19:07

Dmitry


2 Answers

Relationship between the Watch app interface, the WatchKit extension, and the iOS app

Base the relationship, i think KVO doesn't work between watchos and ios, if you want to get the latest data from ios app, there are two ways.

  1. Check the latest data in willActivate
  2. Background Tasks

Background tasks are a way for you to keep your app’s interfaces up-to-date. Receiving a background task object from the system is your signal to perform specific types of operations. The task object defines the type of task to perform and contains any data needed to complete the task. The system delivers background task objects to your app by calling the handleBackgroundTasks: method of your app’s extension delegate.

watchOS supports the following types of background tasks:

  • Background App Refresh Tasks. Use a WKApplicationRefreshBackgroundTask object to handle general updates to your app’s state. For example, you might use this type of task to check in with your company’s server or begin downloading new content. You schedule this type of background task explicitly from your your app’s WKExtension object.
  • Background Snapshot Refresh Tasks. Use a WKSnapshotRefreshBackgroundTask object to update your app’s interface in preparation of having its snapshot taken. The system automatically takes the snapshot when this task completes. The system schedules background snapshot refresh tasks periodically to update your snapshot. You can also schedule a task of this type explicitly from your app’s WKExtension object when your interface changes.
  • Background Watch Connectivity Tasks. Use a WKWatchConnectivityRefreshBackgroundTask object to receive data sent by your iOS app using the Watch Connectivity framework. The system automatically creates this type of task when your Watch app receives data from the its corresponding iOS app running on the paired iPhone. You do not schedule tasks of this type yourself.
  • Background NSURLSession Tasks. Use a WKURLSessionRefreshBackgroundTask object to receive data you previously requested using an NSURLSession object. This task is triggered when a background transfer requires authorization or when a background transfer completes (successfully or unsuccessfully). You do not schedule tasks of this type yourself.

Remember that background transfers may not be delivered immediately. Files and contextual data are delivered as quickly as possible, but transfers are not instantaneous. Data files involving large files or large amounts of data also take a commensurately long time to complete.

like image 117
Victor Zhu Avatar answered Oct 19 '22 02:10

Victor Zhu


I know that this is a bad way, but i didn't find any others... My way is endless cycle:

var NeedCheking = Bool()


override func willActivate() {
        super.willActivate()
        NeedChecking = true
        CheckDefaults()
}

override func didDeactivate() {
    NeedChecking = false
    super.didDeactivate()
}

func CheckDefaults(){

        let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
        dispatch_async(dispatch_get_global_queue(priority, 0)) {

        repeat {

            let sharedDefaults = NSUserDefaults(suiteName: "group.com.myappname.defaults")
            let NewData = sharedDefaults?.objectForKey("DataKey") as! [[AnyObject]]
            if NewData != self.MyData {

                dispatch_async(dispatch_get_main_queue()) {
                    self.MyData = NewData
                    //Here do update actions!
               }
            }
            sleep(2)
        }while self.NeedChecking
    }
    }

If anybody know other way, please post your solution as answer to this question!

like image 26
Dmitry Avatar answered Oct 19 '22 04:10

Dmitry