iOS: App Groups missing user default key - ios

I have an App with a today extension. I created already an app group in the developer portal and created the target in my xcode project, linking the group in the capabilities for my app and today target.
So at the app side I'm saving my values like this:
NSUserDefaults *prefs = [[NSUserDefaults alloc] initWithSuiteName:suite];
[prefs setObject:value forKey:key];
[prefs synchronize];
The suite property is the name of my group created in the developer portal. Value is a NSDictionary.
NSDictionary* savedDict = [prefs objectForKey:key];
Calling this gives me the correct values
At the Extension Side I'm using swift and trying to get my UserDefaults like this
let userDefaults = UserDefaults.init(suiteName: "group.cryptochange.favorites")
let savedDict = userDefaults?.dictionary(forKey: "Favorites");
The problem is, that savedDict is nil.
When I print out all keys in my user defaults I see the "Favorites" key at the app side but if I'm printing out the keys in the extension, this key is missing.
Does anybody know where or what the problem could be?
Thanks in advance
EDIT 1:
I just recognize that it works with a debug build but not when I change the scheme to release
EDIT 2:
I just checked the documents directory of my app and see my app groups file which includes the values I saved.
When I look up at the documents dir of the extension there is no such a file. Is this works as intended?
After I set an "test" value inside my extension code the file appears with the test value

You have to make sure:
suite = "group.cryptochange.favorites"
key = "Favorites"
You have to check Extension is a member of group app
You should review that "Cast type" is correct
I hope my answers are useful

Related

Using NSUserDefaults to share data between iOS and watchOS?

I'm having an issue with storing NSUserDefault strings in my iOS application and retrieving them on WatchOS.
I used the following tutorial for creating App Groups & using NSUserDefaults for App groups: http://www.atomicbird.com/blog/sharing-with-app-extensions
In the end, after creating app groups that didn't seem to have any provisioning errors, and then trying to retrieve my stored string, the value remained null. (Even though the value I was storing was definitely not null)
Here's my code for storing (in HomeViewController.m):
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:#"APP GROUP ID"];
[myDefaults setObject:totalDonatedString forKey:#"donatedForWatch"];
And retrieving (in InterfaceController.m in willActivate):
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:#"APP GROUP ID"];
NSString *donatedWatchString = [myDefaults objectForKey:#"donatedForWatch"];
NSLog(#"%#", donatedWatchString);
[_totalDonatedLabelWatch setText:donatedWatchString];
I'm pretty new to iOS dev/Obj c so any help please!
To share data your approach is quiet right by using 'App Group'. Create a header file which is included in main app target. Define a macro which identifying your app group. For example declare a Constant.h which included as following
#ifndef CONSTANT_H
#define CONSTANT_H
#define SHARED_APP_GROUP #"name_of_your_app_group"
#endif
import this file wherever you want to access (in watchos app related files and main app files) the app group.
For WatchOS 2 and greater: https://telliott.io/2015/08/11/how-to-communicate-between-ios-and-watchos2.html
The guide has instructions for Swift and Obj-C
Thanks to #dan!

Storing bool in shared NSUserDefaults always returns false

I've set up App Groups for my app so that I can access the same NSUserDefaults in the app and in my keyboard extension. I have a problem though. I can successfully write a boolean to the defaults but when I access it in the keyboard, it always returns false. I know for a fact the id it's using for the key and the suite name are the exact same. I verified App Groups is indeed enabled for both the app and the keyboard and the suite name matches the app group identifier exactly. What could cause it to always be false when accessing from within the keyboard?
In the app:
NSUserDefaults *SharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.myname.sharedPrefsName"];
[SharedDefaults setBool:YES forKey:#"com.myname.appname.dataName"];
[SharedDefaults synchronize];
I did confirm it did successfully get set to YES the next time I launch the app:
NSUserDefaults *SharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.com.myname.sharedPrefsName"];
BOOL dataIsYes = [SharedDefaults boolForKey:#"com.myname.appname.dataName"]; //YES
Yet in the keyboard it is always false:
let sharedprefs = NSUserDefaults(suiteName: "group.com.myname.sharedPrefsName")!
let data = sharedprefs.boolForKey("com.myname.appname.dataName") //false
I found the answer in the App Extension Programming guide.
By default, a keyboard has no network access and cannot share a container with its containing app. To enable these things, set the value of the RequestsOpenAccess Boolean key in the Info.plist file to YES.
To fix the issue I had to change the RequestsOpenAccess field to YES in the keyboard's Info.plist > NSExtension > NSExtensionAttributes > RequestOpenAccess. Then remove the keyboard in Settings, delete the app, run it again, and add the keyboard again. Then be sure to tap on the keyboard name and then flip the switch to Allow Full Access.
If users don't enable Full Access, the extension will still be able to access the shared container (iOS 8.3+ only) but it will not be able to write to it, for security and privacy reasons. In 8.2- you cannot read from it without open access granted.
Don't use alloc/init for NSUserDefaults. It's a singleton. You're supposed to use the class method
standardUserDefaults to get a pointer to the shared user defaults object:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

Can't share data between app and today extension

I am developing to-do list app. In this app, i add the today extension. It is used to show the to-do list for today.
This is the code for share data between app and today extension. For testing purpose i add the only one item in the NSUserDefaults.
App code for saving the data to NSUserDefaults.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.compname.appname"];
[shared setValue:#"Test" forKey:#"test"];
[shared synchronize];
Today extension code for fetch the data from NSUserDefaults
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.compname.appname"];
NSString *str = [ shared valueForKey:#"test"] ;
NSLog(#" Text = %#", str);
I am always getting the 'null' value.
Sounds like you haven't added the group to the entitlements/capabilities.
From this site: http://www.shinobicontrols.com/blog/posts/2014/07/21/ios8-day-by-day-day-2-sharing-extension
Go to the capabilities tab of the app's target
Enable App Groups
Create a new app group, entitled something appropriate. It must start with group.. In the demo the group is called group.ShareAlike
Let Xcode go through the process of creating this group for you.

NSUserDefault can't save & load in Extension in iOS8

I need to save data to NSUserDefault in my iOS Custom Keyboard.
I have successfully created App Groups and entitlement in developer portal and XCode.
Here is how i save my value with UISwitch
- (IBAction)switchAction:(id)sender
{
[self.defaults setBool:self.myKey.on forKey:#"myValue"];
[self.defaults synchronize];
}
and here is how i load value in KeyboardView.
self.defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.mycompany.customkeyboard"];
if([self.defaults boolForKey:#"myValue"])
{
self.backgroundColor = [UIColor redColor];
}
else
{
self.backgroundColor = [UIColor blackColor];
}
It's doesn't work and doesn't load value.
How can i save and load data?
Initialize your NSUserDefaults object like this in all applications in the app group and they will share the database:
[[NSUserDefaults alloc] initWithSuiteName:#"group identifier"];
Keep in mind everything from the [NSUserDefaults standardUserDefaults] database for each application will not carry over into this database.
The documentation indicates that [NSUserDefaults standardUserDefaults] should return the shared database like the above code does, however it does not. I filed this as a bug (rdar://17164758).
And don't forget to synchronize the database:
[yourDefaults synchronize];
Ok, So I had a look around becuase I had the exact problem. What I did that worked was to add the main app and the extension to a group, Go to main project->Target->Capabilities and create a group (if you don't have one, or make one anyway) like this:
Then, go to the Extension below the target (E), again to Capabilities and add the extension to the group (exactly the same app group as you did for the main target), like this:
Then, once you have done both, in your main app, whenever you want to add something, create a new instance of NSUserDefaults, but for the Suitename equal to the groupname you made earlier. Like this:
NSArray *testing = #[#"first",#"Second",#"Third"];
NSUserDefaults *userd = [[NSUserDefaults alloc]initWithSuiteName:#"The gouprname I made earlier"];//This is exactly the same as the groupname
[userd setObject:testing forKey:#"ExtensionArray"];//set the object you want to share
[userd synchronize]; //It's a good idea to sync, just to be on the safe side.
In your extension's ViewController, use the same group name but to read the user defaults:
NSUserDefaults *sharedD=[[NSUserDefaults alloc]initWithSuiteName:#"Exactly the same groupname that I gave both in the Capabilities and when initialising the userdefault"];
self.testing = [[NSArray alloc]initWithArray:[sharedD arrayForKey:#"ExtensionArray"]];
And Voila! the array is there! I read somewhere that you can even add notification functionality for when the object changes, using a Wormhole class, but I can't find the link to it. I'm sure if you google for Wormhole class, you'll come across it.
I hope I could help, and if you found any more info, please share it with me.
You could load the right data from the containing app, so maybe set a new value in extension app will help.
[self.defaults setObject:newValue forKey:#"thisKeyIsJustUsedForSyn"]
And then load the right data.

Settings bundle not syncing up with NSUserDefaults [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Multivalue type settings bundle fields alway return null
I have a settings bundle in my iOS app which generates the following table in the settings app
In my app I attempt to generate the same table using NSUserDefaults and end up with this
My code to retrieve the values goes is:
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
ds->use_cache = [userDefaults boolForKey:#"use_cache"];
ds->high_bitrate = [userDefaults boolForKey:#"high_bitrate"];
and
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[[cell detailTextLabel] setText:[defaults stringForKey:#"version"]];
The stringForKey with the key "version" always returns a null value. I can't seem to get my app to recognise the default parameters I have defined in the settings bundle.
Here is my settings bundle
The default values for the settings should be set using the registerDefaults: method. This sets up an NSRegistrationDomain from which they will be available. An example for this is below. Thanks to jrturton & Matthias Bauch for pointing out the problem with my first answer that was previously referring to http://greghaygood.com/2009/03/09/updating-nsuserdefaults-from-settingsbundle.
NSDictionary *appDefaults = [ NSDictionary
dictionaryWithObject:#"default_version_value" forKey:#"version" ];
[ [ NSUserDefaults standardUserDefaults ] registerDefaults:appDefaults ];
NSUserDefaults *userDefaults = [ NSUserDefaults standardUserDefaults ];
Also note these default values need to be set every time the application starts as stated in the documentation for registerDefaults:.
The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.

Resources