6

Apple documentation says "Also, iOS automatically forwards a read-only copy of your iOS app’s preferences to Apple Watch. Your WatchKit extension can read those preferences using an NSUserDefaults object...". https://developer.apple.com/library/prerelease/watchos/documentation/General/Conceptual/WatchKitProgrammingGuide/SharingData.html#//apple_ref/doc/uid/TP40014969-CH29-SW1

But I can't read defaults in my WatchKit app that were saved in my iPhone app, am I doing something wrong?

In the WatchKit app, can I even save to (a WatchKit only) defaults, or does that not even work?

iPhone Data:

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(dataArray, forKey: "DataSaved"

Watch ExtensionDelegate:

let defaults = NSUserDefaults.standardUserDefaults()
print(defaults.arrayForKey("DataSaved"))
print(defaults.objectForKey("DataSaved"))

arrayForKey and objectForKey for print nil.

I must be doing something wrong, do you know what it would be?

victorpulak
  • 131
  • 2
  • 8

4 Answers4

11

Difference between NSUserDefaults

NSUserDefaults is a unit of memory on any device, so it is completely different in iOS and watchOS, as well in tvOS, etc.

For example, if you run a code that adds a new key called "key1" to NSUserDefaults on iOS (assuming you are using NSUserDefaults.standardUserDefaults()) , when you request to read its data on watchOS, it gives you an empty dictionary.

That's because it the first time, you store the dictionary only in iOS App Target and not in a shared space between two devices. When the WatchKit extension wants to use NSUserDefaults, it reads the (empty) dictionary saved in WatchKit Target and not the (filled) dictionary in iOS Target.

Sharing Data

There are some ways of sharing dictionaries between watchOS and iOS:

1- Using WatchConnectivity framework in watchOS 2, you could pass data between two targets. You can use sendMessage or similar functions in WCSession classes to do so. Just don't forget to add WCSessionDelegate to your InterfaceController (in watchOS) or ViewController (in iOS) classes and app delegates for the app to be able to receive data from WatchConnectivity.

2- Using online/cloud storages, you could upload the dictionary from iOS App there, and then download it to watchOS App. However, this needs an Internet connection, and is not suitable in many cases, for example if your app does not need to connect to the Internet to do other tasks, and you force the user to connect to the Internet just in order to sync a simple dictionary between the two targets.

3- Using App Groups (if you are using watchOS 1), which I don't describe it more, because it is outdated and you probably don't want to make your app just for watchOS 1.

Conclusion

1- NSUserDefaults returns two different dictionaries in watchOS and iOS, respectively.

2- To share data between watchOS and iOS, you could use WatchConnectivity, the Internet (not recommended) and App Groups (in watchOS 1).

More Resources

For more details about WatchConnectivity, the modern answer to your question, you should check out Apple Documentation in Apple Developer Portal.

Also you should see this WWDC session talking about this great framework included in watchOS 2.

Seyed Parsa Neshaei
  • 3,470
  • 18
  • 30
  • 1
    "NSUserDefaults returns two different dictionaries in watchOS and iOS, respectively." was the part I needed thanks – victorpulak Mar 27 '16 at 14:25
  • You are welcome. I'm glad that I could solve your problem. – Seyed Parsa Neshaei Mar 28 '16 at 08:44
  • 1
    this answer is lack of information. In [apple docs](https://developer.apple.com/library/content/documentation/General/Conceptual/WatchKitProgrammingGuide/SharingData.html#//apple_ref/doc/uid/TP40014969-CH29-SW1): `Additionally, iOS automatically forwards a read-only copy of your iOS app’s preferences to Apple Watch. Your WatchKit extension can read those preferences using an NSUserDefaults object, but it cannot make changes directly to the defaults database` – Sang Feb 27 '17 at 13:22
  • @transang, have you actually seen this behavior? I see that doc as well but I can't see any evidence it is actually true from my experience with watchOS. – RealCasually Apr 04 '18 at 05:44
3

Sorry. You can't read any defaults in WatchKit app, because from watchOS2 it has it's own memory to be used. so You can not access value from iOS's NSUserDefaults in watchOS

You have to use WatchConnectivity to share data for watch OS2.

Ashish Sahu
  • 388
  • 3
  • 16
  • I think you referenced a prerelease version of watch os, so it might not be accurate now. – Nicolas S Mar 17 '16 at 13:50
  • @NicolasS ah, I see. Do you know if there is an updated doc of that, because I don't see anything about NSUserDefaults that has been updated since then that I can find. Thanks! – victorpulak Mar 18 '16 at 22:48
2

To be clear, NSUserDefaults.standardUserDefaults() will give you two different dictionaries when calling on the watch and on the phone.

For WatchConnectivity check out https://developer.apple.com/videos/play/wwdc2015/713/

Apple docs:

https://developer.apple.com/library/watchos/documentation/WatchConnectivity/Reference/WatchConnectivity_framework/index.html

Nicolas S
  • 5,325
  • 3
  • 29
  • 36
  • Oh wow, I had no idea. Do you have the Apple Doc that references that, or something else that references that, so I can start to wrap my head around how that works? – victorpulak Mar 17 '16 at 13:46
  • I don't see anything about NSUserDefaults there? – victorpulak Mar 17 '16 at 13:56
  • WatchConnectivity won't give you access to the NSUserDefaults. However, from within your phone app, you could use WatchConnectivity to send a copy of the defaults to your watch app. The watch app could use the received object, and if changes need to be made, send the changes back to the phone app. The phone app could then write those changes to it's NSUserDefaults. – Josh Buhler Mar 17 '16 at 17:52
  • @JoshBuhler the problem I'm having is that I'll save and object to NSUserDefaults on iPhone and then not be able to read that object on Watch. I can't do this "The watch app could use the received object" when I've tried it, but being able to do that is what I'm hoping to do – victorpulak Mar 18 '16 at 14:41
  • @victorpulak Have you tried sending data from your phone to the watch using WCSession and the sendMessage:replyHandler:errorHandler message? What happens when you do that? – Josh Buhler Mar 18 '16 at 20:18
  • I was putting this question up so I could find out specifically about the NSUserDefaults part of the equation. I have used all the Watch Connectivity, and was just looking for specific docs on how NSUserDefaults does or doesn't work, since I see conflicting information when I research it. Appreciate the help, if you see anything on NSUserDefaults just let me know – victorpulak Mar 18 '16 at 22:45
  • You need to use watch connectivity transferUserInfo on the dictionary you get from NSUserDefaults on the phone now. The NSUserDefaults will not be transferred for you anymore in watchOS 2. You can write them to the watch NSUserDefaults yourself though. – Cobra Mar 21 '16 at 12:45
  • @Cobra the last sentence was exactly what I was looking for thanks! – victorpulak Mar 27 '16 at 14:24
0

Ns defaults.standard is particular to that target by using it you can access data within that target, in your case you need to access data in another target so listen you need to do two things one is 1. use app groups 2. don't use user defaults.standard use UserDefaults(suiteName:"group.yourgroup") to store and access the data refer this Link might be useful.

Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
lokesh
  • 64
  • 4