Am I misunderstanding NSUserDefaults initWithUser? - ios

What I expect to happen:
I create an NSUserDefaults object with a username (NSString of my choosing right?) and when I save defaults it saves those defaults for just that user.
What actually happens:
When I try creating NSUserDefaults for different usernames they are always saved into the same com.companyname.appname.plist file so it seems to ignore the per-user part and just save app-wide.
My Question:
Does this work on iOS or only OSX? What am I missing? Shouldn't I be getting a different plist file per-user? I reviewed the one .plist it does create in xcode and there's nothing in there that tells the default it belongs to a particular username.

Yes you are misunderstanding it, but really it's a badly named method.
Essentially it's to allow Apps that run as root (or superuser) to access the UserDefaults for other users.
In this case, user is a unix user, not some arbitrary partitioning name that you (the developer) chooses.

I am pretty sure, NSUserDefaults is for a app, not a user. It is the defaults for that app. Now it is upto you to model it to store preferences for multiple users. Say using a NSDictionary

NSUserDefaults combines values from different sources.
If you use managed applications in the enterprise, there will be preferences coming from the enterprise device management system.
The application itself will have its own built-in defaults.
On top of that, the application can read and set applications per user; these are stored in the user's library/preferences.
If you do nothing unusual in your app, the preferences from all these sources will be combined, and whatever preferences you save will be stored as preferences for that particular user.
And as a very very unusual special case, apps running as root and not as a particular user can access every user's preferences.

Related

Is data stored in iCloud using Key/Value accessible by users?

I have an application that is implementing storage using Key/Value pairs in iCloud. From what I read in the documentation this is almost identical to the way NSUserDefaults work.
However this potentially creates a problem because the user should not have the ability to tamper with the app data stored in there. Does this mean that the user can access this data and modify it? Or is it private to the application?
Okay reading deeply in the documentation it says
If your app needs to store passwords, do not use iCloud storage APIs
for that. The correct API for storing and managing passwords is
Keychain Services, as described in Keychain Services Reference.
I found this text here just one line before the last table :)
I also found somewhere that the user can delete his iCloud data manually which can be counted as a modification.
Also, read here, section fro "Start Fresh If Your iCloud Data Becomes Inconsistent During Development" where it says how you can clean the container. Maybe you can check what is visible inside.
It depends what type of data you are storing in the iCloud if it's sensitive then I would use keychain services approach and avoid storing sensitive information on the iCloud.
From the question it seems like you are storing the data in key-value pairs, usually, it's recommended to store preferences, settings, and simple app state and that should be ok because the user can change those, you should choose the right iCloud API for what you want to store
With iCloud the user can always delete the information it has stored as mentioned in the documentation
There may be times when a user wants to delete content from iCloud.
Provide UI to help your users understand that deleting a document from
iCloud removes it from the user’s iCloud account and from all of their
iCloud-enabled devices. Provide users with the opportunity to confirm
or cancel deletion
When you ask
Or is it private to the application?
There's an iCloud identifier in your entitlements file. If it's the same in both apps you'll be able to access the same data/documents across both the apps.
Hope that helps.

NSUbiquitousKeyValueStore vs NSUserDefaults

From Apple's NSUbiquitousKeyValueStore documentation:
If you write to the key-value store object when the user is not signed into an iCloud account, the data is stored locally until the next synchronization opportunity. When the user signs into an iCloud account, the system automatically reconciles your local, on-disk keys and values with those on the iCloud server.
Therefore if a user never signs into an iCloud account, the key-value store object is stored locally indefinitely, much like NSUserDefaults.
In this case, should we all stop using NSUserDefaults and just use NSUbiquitousKeyValueStore as a 'default' for all apps? What are the disadvantages of this approach?
An advantage I can see is that from a user perspective the app preferences will be synced across all their devices, which is most likely a better user experience!
We should clearly understand that NSUbiquitousKeyValueStore in the iCloud is for the configuration and tracking of the app state across all devices of the certain account.
Some facts bout NSUbiquitousKeyValueStore.
In the documentation we can find that :
Avoid using this class for data that is essential to your app’s
behavior when offline; instead, store such data directly into the
local user defaults database.
Also size of the data that is possible to save is relatively small.
The total amount of space available in your app’s key-value store, for
a given user, is 1 MB. There is a per-key value size limit of 1 MB,
and a maximum of 1024 keys.
I have found if the user goes into their iCloud settings and turns your app switch off - you will no longer be able to save to NSUbiquitousKeyValueStore.
Your app will start with it enabled. Then you may save data there. Once iCloud is turned off, it will always be accessible to read - but if you update the data and restart the app, i believe you will see it revert back to what it was before the user turned off iCloud support in iCloud settings.
This is a problem I am working with at the moment. I am trying to find a way to test if that switch is on/off and change my data store to NSUserDefaults.
Correct me if I am wrong but that is what I have discovered so far.
-mark
edit: this is only if you have registered for iCloud Documents. If you are ONLY using NSUbiquitousKeyValueStore it should be virtually the same - I believe.
edit-edit: now its acting different. The switch is there when ONLY NSUbiquitousKeyValueStore is checked in the iCloud capabilities. So looking - again - for a way to detect if that switch is flipped for an app in iCloud Settings.

How to save a key value pair that can be accessed by all apps (globally)

I want to save some alpha-numeric value that needs to be accessed by 2 or more apps.
NSUserDefaults is only for within the same app, so I was wondering if there was something similar which can save key value pairs globally.
Additional info: I'm using my first app to save the UDID or some unique key on my phone, so that Appium can later access it.
You can use Shared User Defaults - iOS8+
As long as all your apps are in the same 'App Group' and use the same 'SuiteName' and keys - they can share info there.
Using it is as simple as using regular UserDefaults - you just need a little more setup.
You can find a good guide here:
https://medium.com/ios-os-x-development/shared-user-defaults-in-ios-3f15cd2c9409

Saving app settings - iOS

I have an iOS app which loads certain features depending on the settings that the user sets. Currently I am using NSUseDefaults to save and retrieve these settings and it works fine. But from what I understand anyone can view and edit them with a simple XML editor. You don't even need to jailbreak an iOS device to gain access to them. So they arn't very secure.
I was wandering if anyone could give me some advice on how I can go about saving app settings (these are NONE secure settings, no passwords, just simple things like ints and strings).
Here are a few ideas I had:
IDEA 1 Add a JSON file to the app NSBundle and then edit/save that JSON file every time you want to load/change the app settings.
IDEA 2 Use Keychain - it can store strings right? And it can't be accessed or edited by anyone. (hopefully even the NSA... lol). I could just store an array of strings in keychain for my app settings.
IDEA 3 Store the settings on a server and get the app to pull them down for the user every time they use the app.
IDEA 4 If NSUserDefaults supports this, then maybe locking the NSUserDefaults so that the end user can only view them but not edit them. Only the app will be able to edit them.
The main point is that I am worried that if I use NSUSerDefaults, the user may see them and edit them and then the app will not function properly. While I am not storing any kind of secure data, it would be nice if I can prevent the user from editing the app settings.
Are any of these approaches any good?
Thanks for your time, Dan.
All of them are good ideas, but just one issue with the first one:
You can not write or change files in the main bundle.
As long a the sure did not jailbreak their device the NSUserDefault can not easily be changed.
The keychain should only be used for password, token, etc..
In you case the NSUserDefault will do just fine, or just save the some file the documents directory of your is also an option. You can even create you now settings class that conforms the to NSCoding protocol and you can save it.

iOS: Storing user registration details

I an building my first iOS application and I need to store the user registration details of the user using the application. The details include his mobile number and a unique id( uuid ) which I use to contact with the backend. It would be great if I could get a suggestion on where to store this user details.
Should I be storing this in the NSUserDefaults or should I be using Keychains to store this data or even may be a using a user model in the database ( I would need a database in any case to store a few other details ). Just to add on, I also would like to perform a few validations like if the mobile number is of proper format and so on before I could actually save it. Also can any one please suggest on the security aspects of different storage mechanisms possible here?
Any help on this would be much appreciated.
The most secure way would be to use keychain services as the data is encrypted but in your scenario it seems a bit over kill. I would recommend either just using NSUserDefaults or an sqlite database I wouldn't really recommend storing in a plist as this can be accessed really easily.
But this all depends on the data you are getting, if it was just uuid and mobile number then NSUserDefaults would do probably, whereas if you were getting usernames and passwords and other personal data I would looking a mix of keychain and sqlite database.
Also you could use coredata file to store user data but seems a bit over kill as well for for such little data.
Just a little note you are actually not allowed to get the iPhones mobile phone number programmatically, getting this would use Private APIs that Apple would reject your app for using.
2.5 Apps that use non-public APIs will be rejected
So you would have to ask he user for this.
Database selection is totally depend on the architecture and security, if you just need to store the few information like login details and some field then Keychain for login details and plist for data is best option, but if your application also working with services and fetching and saving lots of data and continuously updating it then a serious database structure required. In that scenario core data and sqlite both are good option depends on your preference
Following ways you can save details.
In NSUserDefaults
In coredata file.
In sqlite database
Plist file.(Not recommended)
You can save data at server site using webservice.
Any one of these you can use according to your requirement and data.
Cheers :)
If you store information on the UserDefaults, a jailbroken device can see the information you have stored, it is a plist after all. If you are going to keep sensitive data on your device, user defaults itself is not a good option. Possible alternatives:
Use keychain: Keychain is a tool to keep usernames & passwords securely on a device; so you may need to find a way to convert all the info you have mentioned ( a dict, I presume? ) into NSData and put into/get from the keychain but it's been explained on other threads. Additionally, keep in mind that when the app is deleted, keychain data will persist on the device.
UserDefaults & encrpytion: If you can encrypt the data yourself, than using UserDefaults might be a better option. Its more straightforward than keychain and it will be deleted if you delete the app from the device (which may be the thing you want, or not. It depends)

Resources