NSUserDefault can't save & load in Extension in iOS8 - ios

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.

Related

iOS: App Groups missing user default key

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

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.

UIWebView must get localStorage item and store it in the app natively / retrive it natively

I have the first part figured out...
- (void)webViewDidFinishLoad:(UIWebView*) myTapView {
NSString *jsString = #"localStorage.getItem('username');";
NSString *someKeyValue = [tapView stringByEvaluatingJavaScriptFromString:jsString];
// This is where I would start storing it so I can retrieve it later
}
So here is my issue, I need to store the value I just got from localStorage so I can use it again. Problem is I don't know where to start. This code is inside my ViewController for the WebView, so I need to be able to use it in other areas in the ViewController.m file.
What is the best method for storing the info? I would also want the above code to be able to update the value, as it won't always be the same username (people can switch accounts).
There are a few ways to store data on iOS, but it depends on what kind of value you want to store. If it's just a plain string or other "light" data, the best approach is to save it to NSUserDefaults. If it's an image or video, you may want to consider archiving it using NSKeyedArchiver. Otherwise, if you want to build a complicated data model, use Core Data.
Here's a good post on NSHipster that describe in detail pros and cons of each approach.
According to your code, you want to store a string. I'd go with NSUserDefaults in this case.
Use NSUserDefaults to store UIWebView local storage value as follows
- (void)webViewDidFinishLoad:(UIWebView*) myTapView {
NSString *jsString = #"localStorage.getItem('username');";
NSString *someKeyValue = [myTapView stringByEvaluatingJavaScriptFromString:jsString];
// Store your Username in iPhone persistence variable and use it later in the application
NSUserDefaults *userdefault = [NSUserDefaults standardUserDefaults];
[userdefault setObject:someKeyValue forKey:#"username"];
[userdefault synchronize];
//use of User default
NSLog(#"User name %#",[userdefault valueForKey:#"username"]);
}

is that possible to know my apps is first time run or not in xcode?

i create an apps that i want to prompt an message for the user.. maybe using UIAlertview. After that, if the user run the apps for the second time, the alert won't prompt up anymore.
is that possible? honestly i don't have any idea about how to doing this.
Any idea? I search on STO, actually this link, still confused.
what is NSUserDefaults? How can NSUserDefaults store this information? i mean this is my first time or second time.
thanks.
To know what's NSUserDefaults, I suggest to take a look the official doc.
And of course you can use it to fulfill your goal.
You use a user default to store information about the current amount of runs in the app.
More or less like:
BOOL isRunMoreThanOnce = [[NSUserDefaults standardUserDefaults] boolForKey:#"isRunMoreThanOnce"];
if(!isRunMoreThanOnce){
// Show the alert view
// Then set the first run flag
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isRunMoreThanOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Yes, U can save a value in NSUserDefault for the first time in your app & set it some other value once you open the app.
like
if(![[NSUserDefault standardUserDefault] objectforKey:#"AppOpenFirstTime"])
{
// App Open First time
// Show Alert
[[NSUserDefault standardUserDefault] setObject:#"1" forKey:#"AppOpenFirstTime"]
}
You can check if you stored some value in NSUserDefaults
NSString *flag = [[NSUserDefaults standardUserDefaults] stringForKey:#"not_first_run"];
if (!flag) {
//first run, do somethig
}
and then set it to some value
[[NSUserDefaults standardUserDefaults] setObject:#"just any string" forKey:#"not_first_run"];
NSUserDefaults is a key-value store saved between your application launches.
You can do it exactly as cortez said in your link. NSUserDefaults is written to disc, and will be created and accessed from your app.
See this link
First Time when your application launch at that time boolForKey:#"AlreadyRan" is FALSE. after that set it TRUE.
if(![[NSUserDefaults standardUserDefaults] boolForKey:#"AlreadyRan"] )
{
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"AlreadyRan"];
}
With the NSUserDefaults class, you can save settings and properties
related to application or user data.
The objects will be saved in what is known as the iOS “defaults system”.
The iOS defaults system is available throughout all of the code in your app, and any data saved to the defaults system will persist through application sessions.This means that even if the user closes your application or reboots their phone, the saved data will still be available the next time they open the app!

How to determine that user runs the app for the first time?

I got a problem of my iOS app recently. In my app, an instruction view will appear at the first time of running, then hide from then on. How can I implement this effect?
Try to use this function:
- (BOOL) isFirstRun
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"isFirstRun"])
{
return NO;
}
[defaults setObject:[NSDate date] forKey:#"isFirstRun"];
[[NSUserDefaults standardUserDefaults] synchronize];
return YES;
}
In your app delegate check for a key in the user defaults (your own custom key, something like "AppWasAlreadyStartedPreviously"). If the key doesn't exist yet, it's the first run. You can show your instruction view and add the key to the user defaults. The next time the user starts the app you'll find the key in the user defaults and know that it's not the first run.
See the documentation of NSUserDefaults.
Store a file and check if the file exsists every time when you start the app. If tr file does not exsists then show intro, and then create the file.
The only way I think is to store a value into a specified file, when run the app, you should check the value first, and then you can deal with the result whether the app has already been run.

Resources