How do I count how many times an ibaction is performed? - ios

I am about to release an iPhone app for a small business. The app has a call button which calls the business with an ibaction. I would like to know if i can find out how many times this action occurs so i can get a better idea of how effective the app is, and how to go about it.
Thanks for your time.

You could implement a web-service with a simple method which will increment a counter on a server. And call it asynchronously every time user taps a button. I would do it like this:
#define TAP_COUNT_KEY #"tapcnt"
#define MAKE_URL(X) [NSURL URLWithString:[NSString stringWithFormat:#"http://my_service_address?cnt=%d", X]]
dispatch_queue_t serviceQueue = dispatch_queue_create("Tap counter queue", NULL);
dispatch_async(serviceQueue, ^{
NSUInteger counter = [[NSUserDefaults standardUserDefaults] integerForKey:TAP_COUNT_KEY] + 1;
NSURL *serviceUrl = MAKE_URL(counter);
NSError *error = nil;
[NSString stringWithContentsOfURL:serviceUrl encoding:NSUTF8StringEncoding error:&error];
if (error)
NSLog(#"%#", [error localizedDescription]);
else
counter = 0;
[[NSUserDefaults standardUserDefaults] setInteger:counter forKey:TAP_COUNT_KEY];
});
dispatch_release(serviceQueue);

On IBAction method, you can increment counter by +1. Then you can store it into NSUserDefaults by key-value pair. And every time, increase counter and store it. So it'll maintain counter state until application will be uninstalled.
int counter;
-(IBAction)click:(id)sender
{
NSUserDefaults *_countDefaults = [NSUserDefaults standardUserDefaults];
counter = [[_countDefaults integerForKey:#"Counter"] intValue];
counter++;
[_countDefaults setInteger:counter forKey:#"Counter"];
[_countDefaults synchronize];
}
Hopefully, you'll get idea.
Thanks.

You can increase your button tag value and access it where ever you want,
-(IBAction)btnPanic:(id)sender
{
UIButton *btn=(UIButton *)sender;
btn.tag=btn.tag+1;
}

Related

iOS: Interface not refreshing

In my app, I create an EKCalendar. Since the calendar could be deleted by the user outside my app, I need to check if that calendar still exists, like so:
-(BOOL)checkForCalendar {
NSArray *calendarArray = [self.store calendarsForEntityType:EKEntityTypeEvent];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *calNameToCheckFor = [defaults objectForKey:#"calendarName"];
EKCalendar *cal;
for (int x = 0; x < [calendarArray count]; x++) {
cal = [calendarArray objectAtIndex:x];
NSString *calTitle = [cal title];
// if the calendar is found, return YES
if ([calTitle isEqualToString:calNameToCheckFor]) {
return YES;
}
}
return NO;
}
I want my UI to update, if a calendar indeed is deleted, as such:
-(void)initCalendarState {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
if (![self checkForCalendar]){
[self.LoginSwitch setOn:NO animated:NO];
[userDefaults setObject:#"0" forKey:#"SwitchedOn"];
}
}
I have put this method in the Application's Delegate
- (void)applicationDidBecomeActive:(UIApplication *)application
Things I observe:
1) If I go through this code step by step in the debugger, it is called on the correct moment, and is executed as expected: running in the main thread, honoring all conditions etc.
2) However: when it gets to updating the UI, ([self.LoginSwitch setOn:NO animated:NO];), nothing happens.
3) When I rerun the project (effectively force quitting it, and restarting) the UI actually IS updated.
What am I missing?
The concrete question is: why isn't my UI updated while the app is running?
Thanks ahead
I think what is happening, is that the changes I made in my local calendar were not fully proliferated through the iCloud sync system. Or something like it. Not sure.
However: to solve my problem, I added
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(storeChanged:)
name:EKEventStoreChangedNotification
object:self.store];
to my app.
and
-(void)storeChanged:(NSNotification *) notification {
[self initCalendarState];
}
This works flawlessly.

Problems with saving an int in NSUserDefaults iOS

I am using the below code to save an int and some other stuff into NSUserDefaults from my AppDelegate. The other array that I'm saving is full of objects that conform to NSCoding, so I don't think that that's an issue. If the current place is not zero, then that means that there is a session in progress, so all the data is loaded. When saving my data, it only saves if the current place is not zero which indicates that there is a session in progress. I know this calls when I exit the app on my physical device because the NSLog message appears in the debugger.
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
if (self.currentPlace != 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = self.places; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:#"places"];
[defaults setInteger:self.currentPlace forKey:#"current"];
NSLog(#"Saving and Quitting b/c we have a place verified!");
[defaults synchronize];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [defaults integerForKey:#"current"];
self.currentPlace = (int)myInt;
if (self.currentPlace != 0) {
NSData *data = [defaults objectForKey:#"places"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.places = [arr mutableCopy];
NSLog(#"Current Place: %i",self.currentPlace);
}
}
I am using my AppDelegate to store data that can be accessed from multiple screens in my app. In the first ViewController, the user is presented with a menu. If the appDelegate's currnentPlace value is not 0, then the option to continue with the loaded data from the AppDelegate is presented. However, this option is never presented. I check the currentPlace int's value using the following in my first view controller:
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// Do any additional setup after loading the view, typically from a nib.
[self setupViews];
self.spinner.alpha = 0;
NSLog(#"Current %i",delegate.currentPlace);
if (delegate.currentPlace == 0) {
self.continueButton.enabled = false;
self.continueButton.alpha = 0.5;
}
else if (delegate.currentPlace != 0) {
self.continueButton.enabled = true;
self.continueButton.alpha = 1;
}
If anyone could see what I'm doing wrong it would be greatly appreciated.
Move your data restoration code block into a method, as below:
- (void)restoreData {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [defaults integerForKey:#"current"];
self.currentPlace = (int)myInt;
if (self.currentPlace != 0) {
NSData *data = [defaults objectForKey:#"places"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.places = [arr mutableCopy];
NSLog(#"Current Place: %i",self.currentPlace);
}
}
Then call this method in application:didFinishLaunchingWithOptions: and applicationWillEnterForeground: methods in AppDelegate.
You need to use
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
in you controller in which you are making the object of AppDelegate class.
If still you are not able to get current value then just store the value in user default as a string and when you acess it, convert it in appropriate data type which you want. Might be this could help you.

High Scores using NSUserDefaults not saving after app shut down

I am really new to iOS programming and forgive me if I sound a bit ignorant but, whenever I try to save a high score within my app using NSUserDefaults I always lose it after the app is shut down.
This is in my viewDidLoad method:
[[NSUserDefaults standardUserDefaults]setInteger:egtTopScr forKey:#"egtSectopScore"];
[[NSUserDefaults standardUserDefaults] synchronize];
[prefs setInteger:egtTopScr forKey:#"egtSectopScore"];
This is what happens to the top score when the game ends:
if(scoreCounter > egtTopScr) {
egtTopScr = scoreCounter;
}
topScore.text = [NSString stringWithFormat:#"Best: %i", egtTopScr];
After the app launches you have to load the integer you saved.
NSInteger score = [[NSUserDefaults standardUserDefaults] integerForKey:#"egtSectopScore"]
// do some stuff with score

Save and Load Data on Today Extensions (iOS 8)

Is it possible to save and load data on Today Extension using NSUserDefaults?
After closing the Notification Center, the widget behaves like an app which is terminated, so any data results lost. How could I solve this issue?
This is my code:
NSUserDefaults *defaults;
- (void)viewDidLoad {
[super viewDidLoad];
defaults = [NSUserDefaults standardUserDefaults];
NSArray *loadStrings = [defaults stringArrayForKey:#"savedStrings"];
if ([loadStrings objectAtIndex:0] != nil) {
[display setText:[NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:0]]];
}
if ([loadStrings objectAtIndex:1] != nil) {
calculatorMemory = [NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:1]].doubleValue;
}
}
- (IBAction)saveData:(id)sender {
NSString *displayString;
NSString *memoryString;
NSArray *saveStrings = [[NSArray alloc] initWithObjects: displayString, memoryString, nil];
defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:saveStrings forKey:#"savedStrings"];
[defaults synchronize];
}
You need to use app group identifier instead of com.*
For instance:
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.company.appgroup"];
Don't forget to synchronise when you store data
[shared synchronize];
You need to add the App Group stuff detailed under here and then if it actually worked (pretty iffy under beta) it should allow you to share NSUserDefault data like normal between the host and widget.
Edit: Normal NSUserDefaults does not work. Apple has implemented a new method. To use, simply redefine your NSUserDefaults instance like this:
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"com.you.app.container"];
For anyone wondering how in the world do you save and get values then look at this code.
In your regular app add this to save whatever you like in your *.m file.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.yourcompanyname.TodayExtensionSharingDefaults"];
//save dic
[shared setObject:dictionary2 forKey:#"dicForTodayWidget"];
//save array
[shared setObject:tempArray2 forKey:#"arrayForTodayWidget"];
//save some value
[shared setObject:#"1234" forKey:#"myValForTodayWidget"];
[shared synchronize];
In your today widget under TodayViewController.m in viewDidLoad add this.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.yourcompanyname.TodayExtensionSharingDefaults"];
//get dic
NSMutableDictionary *dictionary = [shared objectForKey:#"dicForTodayWidget"];
You first need the App Groups set up for both targets (application and the extension).
Then, use the
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.company.myapp"];
to obtain the defaults object which you can read from/write to as usual.
If you want to be notified of changes to the defaults, use the NSUserDefaultsDidChangeNotification in your widget (or app).
For a step-by-step tutorial explaining all this, take a look at this blog post.
#edukulele
Today Extension and Main app run on two processes. Today Extension can't receive NSUserDefaultsDidChangeNotifications. I tried use MMWormhole. It is very good.

NSUserdefaults not updating till the application restarted

I am pasring json data from a url and taking one of teh values to NSUserdefaults to use it it application view .
Example user will enter an unique code given to him and this code will be appended to the requested URL , accoridng to the requested code the json value will be changed .
At present when i enter code it is fetching and saving NSuserdefaults and passing it to the label filed in view . But when i enter new code and fecth new data it is not updating in the view . If i restart the application and enter new code then it is showing new Value . Can somebody help me . here is the code
NSString *jsonUrlString = [[NSString alloc] initWithFormat:#"http://mywebsite.com/json/code.php?user=%#",_opcodeField.text];
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
[_indicator startAnimating];
_indicator.hidesWhenStopped = YES;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//-- JSON Parsing
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"settings = %#",result);
for (NSDictionary *dic in result)
{
[[NSUserDefaults standardUserDefaults] setObject:[dic objectForKey:#"footer"] forKey:#"op_footer"];
[[NSUserDefaults standardUserDefaults] synchronize];
[_indicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
}
View code is:
(void)viewDidLoad {
[super viewDidLoad];
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
How can I show new values without restarting application . Is there any code to be added in view ? I can see json is fetching correctly newvalues when user entered new code
Thank you.
Are you sure viewDidLoad is the best place to add this code?.
Try to add your code in some method which is called more often. For debugging I usually add some button just to call a NSLog to see what happens.
Try this if you want to load the text all the time you come to the viewcontroller.
- (void)viewWillAppear:(BOOL)animated {
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
}
Or you can try this if you want to load it to a label after getting the new code.
- (void)updateLabel {
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
}
Hope this helps.. :)
Why not move this line...
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
to here (unless of course this is in a different class)...
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"settings = %#",result);
for (NSDictionary *dic in result)
{
[[NSUserDefaults standardUserDefaults] setObject:[dic objectForKey:#"footer"] forKey:#"op_footer"];
[[NSUserDefaults standardUserDefaults] synchronize];
[_indicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
}
//Update it straight away
_Footer.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"op_footer"];
Also bit confused why you are looping through dictionaries here? Is there more than one dictionary? If there is the last value will always be the one that gets stored in UserDefaults.
You are also stopping the animation in the loop as well?
The user defaults plist can take time to save and update. It doesn't happen instantly. Try triggering the call after a pause of some kind. Test with a button.
Edit: you can add an observer to the default so that you know it has updated - Cocoa - Notification on NSUserDefaults value change?

Resources