Dynamic values for MultiValue in Watchkit Settings Bundle - ios

I'm having trouble understanding how I can have dynamic data fed into a MultiValue attribute inside the Root.plist file of a Settings-Watch.bundle.
When fetching some REST API I would like to retrieve some map (dictionary) and set that data as the list of choice in my Watch Settings Bundle so that the user can select a specific value from it inside the Apple Watch application on the iPhone/iPad.
I tried like this:
NSUserDefaults *watchPrefs = [[NSUserDefaults alloc] initWithSuiteName:#"group.foo"];
// foo and titles are NSArray* of NSString.
// I also tried by giving it a NSDictionary* whose keys are what's in foo and values reflecting bar
[watchPrefs registerDefaults:#{#"preferedAccount": #{#"Values": foo, #"Titles": bar}}];
[watchPrefs synchronize];
But even when I close the app these data are not shown in the Watch application > My application.
I configured the preferedAccount as a MultiValue inside the Root.plist file.
It must be dynamic in that case because the data reflects the logged user and so cannot be known in advance.
Is it even possible to display dynamic data there ?
Thanks

Related

Object reference not set to an instance of an object in xamarin ios app group

I am trying to build today widget in Xamarin.
In the simulator everything works, but when I run it on real device my widget crashes with the following exception:
object reference not set to an instance of an object.
My code is:
var defs = new NSUserDefaults("group.com.gto.extension", NSUserDefaultsType.SuiteName);
defs.Synchronize();
var equities = defs.ValueForKey(new NSString("key1"));--> this row crashes my widget.
There is a difference in-between trying to access the NSUserDefaults for a single application or a group hereof. The latter is what you are currently trying to achieve. I will try to summaries the difference between the two strategies in this answer.
App Group User Defaults
I assume you're trying to read an entry from the NSUserDefaults from another application or extension you have made? Only in that case it is sensible to use the NSUserDefaults of the given. If so, you need to ensure the following:
First, you will need to ensure that the App Group and the required App IDs have been properly configured in the Certificates, Identifiers & Profiles section on iOS Dev Center and have been installed on in the development environment.
Next, your App and/or Extension projects will need to be one of the valid App IDs created above, that the Entitlements.plist file has the App Groups enabled and specified and that it get's included in the App Bundle.
With this all in place, the shared App Group user Defaults can be accessed [...]
https://developer.xamarin.com/guides/ios/application_fundamentals/user-defaults/#Accessing_an_App_Group_NSUserDefaults_Instance
The two points mentioned above may be the reason to why your application is crashing.
Single-application User Defaults
If on the other hand you only need to access a value from the NSUserDefaults of the current application, you can simply do as follows:
var defs = NSUserDefaults.StandardUserDefaults;
Reading the values
To read values from the NSUserDefaults, as seen in the guide and documentation, you should do as follows:
var boolForKey = defs.BoolForKey("key");
var stringForKey = defs.StringForKey("key");
....
Where "key" parameter is the key for the value you previously stored in your NSUserDefaults dictionary.
It would most likely also be sensible to surround any calls to retrieve values from the NSUserDefaults in a try/catch. The key may not yet exist in the NSUserDefaults, which is most likely the issue in your case.

Using NSUserDefaults to share data to watchkit

I am trying to use NSUserDefaults to share my data with the WatchKit files. I am trying to have it so when the button function is executed the watchLabel.setText to data from an array. The array and function that selects the data was created in the iOS application. (Unfortunately many resources I come across are in objective-C or extremely vague.)
I have set up app groups for both iOS and Watchkit
In my iOS Swift file I am trying to share my array(arrayBook) and function(.randomData) to use with the WatchKit controller. PS: I have no compiler errors.
let sharedDefaults = NSUserDefaults(suiteName: "group.applewatchtest")
sharedDefaults?.arrayForKey(arrayBook.randomData())
sharedDefaults?.synchronize()
Watchkit Controller; Unsure the correct syntax for fetching data and setting the label to random string from the array. - This is within the UIButton func.
let sharedDefaults = NSUserDefaults(suiteName: "group.applewatchtest")
let sharedArray = sharedDefaults?.arrayForKey("Shared")
watchLabel.setText(arrayBook.randomData())
Where am I going wrong when fetching the data to set the label to data from the array which is stored in my iOS application.
sharedDefaults?.arrayForKey(arrayBook.randomData())
This line of code is not doing anything. You're reading the array from defaults, using a key of whatever arrayBook.randomData() returns, and doing nothing with it.
I assume you want something like
sharedDefaults?.setObject(arrayBook, forKey:"Shared")
Which will write that array into defaults. You then get it back out in the watch (which looks fine) and get a random value using randomData().

Saving Preference for iOS 8 custom keyboard

I can't find any tutorial or guide to show me how to save preferences with my Custom iOS 8 keyboard.
I have different skins and the user can cycle to all the skins. However if the user dismisses the keyboard then loads it back up, it will load the initial skin.
I know other keyboards have found a way to load Skins and remember which one was selected.
I also have 2 different layouts for my keyboard
QWERTY and DVORAK
I would like to also save that preference so user can change their selection when in my app.
Keyboard is done in Swift/Obj-C (not sure if that matters)
1. Create an app group for your host app and your custom keyboard
Select your host app's target, go to Capabilities, scroll to App Groups and add one by clicking on "+" sign. Type the name of your group.
Do the same with your keyboard's target but now simply add a group by ticking the recently added app group.
2. Now you can use NSUserDefaults to store & share data with your host app
Store data:
_userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.app-group-name"];
[_userDefaults setObject:#"theme-dark" forKey:#"KeyboardTheme"]; // save data
Restore data:
_userDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.app-group-name"];
_theme = [_userDefaults objectForKey:#"KeyboardTheme"];
if ([theme isEqualToString:#"theme-dark"])
{
...
}
- Use constants & NS_ENUM instead of comparing strings.
- Full access has to be activated.
Apple Resources: head for “Sharing Data with Your Containing App“
I know I need to use NSUserDefaults but not sure how to implement it.

NSUserDefaults behaving erratically

Can I know how exactly NSUserDefaults works?
I'm using it to maintain user info like username.
In one controller I set :
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:#"xyz" forKey:#"username"];
and in another one I retrieve it as :
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
username = [prefs stringForKey:#"username"];
It works sometimes, but sometimes the setobject doesn't set anything ( username = [prefs stringForKey:#"username"]; gives me nil. Sometimes it works fine. I thought this was a persistent storage so I'm not sure what's happening. This is in simulator as I haven't got the chance to test it on a phone yet.
This is what Mac Developer Library is saying about NSUserDefaults
The NSUserDefaults class provides a programmatic interface for interacting with the defaults system. The defaults system allows an application to customize its behavior to match a user’s preferences. For example, you can allow users to determine what units of measurement your application displays or how often documents are automatically saved. Applications record such preferences by assigning values to a set of parameters in a user’s defaults database. The parameters are referred to as defaults since they’re commonly used to determine an application’s default state at startup or the way it acts by default.
At runtime, you use an NSUserDefaults object to read the defaults that your application uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.
The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see Preferences and Settings Programming Guide.
Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable.
A defaults database is created automatically for each user. The NSUserDefaults class does not currently support per-host preferences. To do this, you must use the CFPreferences API (see Preferences Utilities Reference). However, NSUserDefaults correctly reads per-host preferences, so you can safely mix CFPreferences code with NSUserDefaults code.
If your application supports managed environments, you can use an NSUserDefaults object to determine which preferences are managed by an administrator for the benefit of the user. Managed environments correspond to computer labs or classrooms where an administrator or teacher may want to configure the systems in a particular way. In these situations, the teacher can establish a set of default preferences and force those preferences on users. If a preference is managed in this manner, applications should prevent users from editing that preference by disabling any appropriate controls.
Would u mind trying this.
[[NSUserDefaults standardUserDefaults] setObject:#"xyz" forKey:#"username"];
than doing like the way u are doing .
And Check the Value by using
NSLog(#"%#",[NSUserDefaults standardUserDefaults] objectForKey:#"username"]);

Dynamic In-App Settings

I have an app where Location is important. Currently I have a multi-value setting in the settings bundle where I have 5 locations defined. The problem with this approach is that the settings bundle is static - i.e. I cannot update that from a JSON list on my server as far as I know.
I want to update the location list from a dynamic list on the server.
I have looked at InAppSettingsKit but this also uses the standard settings bundles. Is it possible to use InAppSettingsKit to import settings updates dynamically from a remote list.
Are there other ways to do what I am trying to do?
You won't be able to change the list dynamically with regards to Settings.app. Settings.app always uses the static schema plist from your app bundle. (You could resort to a freeform text field but that probably doesn't catch your case.)
With InAppSettingsKit, you can accomplish that but you have to do some extra work: For the dynamic parts, you'll want to use a custom view controller, e.g. a table view controller.
Best way for you handle this is storing the multi-values in the NSUserDefaults and start using them. In this method, you will be able to update the values as well as it will be persistent across multiple sessions.
Edit (answers comment):
Saving it to user defaults.
NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
#"your Object", "Your Key"
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
[[NSUserDefaults standardUserDefaults] synchronize];
Retriving it:
[[NSUserDefaults standardUserDefaults] integerForKey:#"Your Key"];

Resources