I want to do something like this in my iOS app. Let's say user open the app now. then I want to show a view. during that 1st hour, no matter how manytimes he open the app I need to show the 1st view through out this hour. when start a new hour I want to show the view 2. again after the 3rd hour I need to show that first view.
Like wise
1hr - view 1
2hr - view 2
3hr - view 1
4hr - view 2
How can I monitor this hours changing from my ios app even its not runing in the background
Thank you
If the app isn't running in the background, you really can't monitor the hour changing. But that doesn't matter since you can't show a view when the app is not running.
When the app is running, just use NSTimer and set it to repeat at the right time to tell your controller that the hour is changing. Let the controller deal with figuring out which view to show.
This is important, because you have to make the decision of which view to show even when the hour isn't changing. For example, when you first open the app.
See NSTimer
AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setObject:[NSDate date] forKey:#"kTimeInterval"];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationNameForBecameActive object:nil userInfo:#{kUserInfoForBecameActive: self.currentTime}];
}
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didBecomeActive:) name:kNotificationNameForBecameActive object:nil];
}
- (void)didBecomeActive:(NSNotification *)notification {
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSDate *previousDate = [standardDefaults objectForKey:#"kTimeInterval"];
NSTimeInterval secondsPassed = [[NSDate date] timeIntervalSinceDate:previousDate];
if (secondsPassed >= CHECK_SWAP_VIEW) {
// Change your view here.
}
}
Here you can do like save time when application goes in background or quit. Then whenever application will open check for previous time and then swap your views.
Related
So I've been doing a bit of research on how to tell if it's a new day in my iOS app. Basically, I want to reset a bunch of values to 0 as soon as a new day starts. I've seen that I can use "UIApplicationSignificantTimeChangeNotification" which sends a notification at midnight. However, will this still fire if the user killed the app at 9:00AM and opens it up again at 9:00AM the next day?
I also saw that I could use "NSCalendarDayChangedNotification" which to my understanding has the same behavior. My only concern is that if either of these will accomplish detecting a day change even after the user kills the app.
Ideally I'd like to put add the notification observer at the top of my .m file in the viewDidLoad like so:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(resetValues) name:UIApplicationSignificantTimeChangeNotification object:nil];
and then somewhere else in the file...
- (void)resetValues {
... // reset values to 0
}
The goal would be for this notification to trigger at the beginning of every day change. Would the code above achieve the behavior I'm looking for?
Solution which saves an integer value (the day) in NSUserDefaults
In AppDelegate create a method checkDayChange which compares the day component of the current date with a saved value in NSUserDefaults (default is 0). If the values are not equal, call resetValues and save the current day.
- (void)checkDayChange
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger currentDay = [[NSCalendar currentCalendar] component:NSCalendarUnitDay fromDate:[NSDate date]];
NSInteger savedDay = [defaults integerForKey:#"day"]; // default is 0
if (currentDay != savedDay) {
[self resetValues];
[defaults setInteger:currentDay forKey:#"day"];
}
}
Observe NSCalendarDayChangedNotification with selector checkDayChange
Call checkDayChange also in applicationDidFinishLaunching and applicationDidBecomeActive
System observer:
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(reloadData) name:NSCalendarDayChangedNotification object:nil];
https://developer.apple.com/documentation/foundation/nscalendardaychangednotification?language=objc
I need show changes in external screen with UIImageView when my ios app is on background mode.
I use this code to change the UIImageView
campaingTimer = [NSTimer scheduledTimerWithTimeInterval:timeFirstAd target:self selector:#selector(changeImage) userInfo:nil repeats:NO];
This works when my app is active, but when in background, enters the changeImage method, but not change the picture.
NSTimer selectors are not guaranteed to fire off in the background. Unless you're registering for specific permissions, such as playing music in the background, and whatever you're actually doing in the background is directly related to the permission you asked for, you should work under the assumption you will not be able to execute code while the app is backgrounded, as that'll set you up to succeed much better than trying to find workarounds.
In this scenario, it seems like you want to change the image after so much time passes. That NSTimer you have (assuming your methods are written correctly) will work while the app is in the foreground, but to deal with background I recommend listening for the appDidEnterBackground and appWillEnterForeground and posting notifications (see sample code below).
AppDelegate.m
================
- (void)applicationDidEnterBackground:(UIApplication *)application
{
self.currentTime = [NSDate date];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationNameForBecameActive object:nil userInfo:#{kUserInfoForBecameActive: self.currentTime}];
}
================
ViewController.m
================
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didBecomeActive:) name:kNotificationNameForBecameActive object:nil];
}
- (void)didBecomeActive:(NSNotification *)notification
{
NSDate *sleepDate = notification.userInfo[kUserInfoForBecameActive];
NSTimeInterval secondsPassed = [[NSDate date] timeIntervalSinceDate:sleepDate];
if (secondsPassed >= timeFirstAd)
{
[self changeImage];
}
// reinitialize NSTimer
}
================
Alternatively, you could post notifications for both appDidEnterBackground and appWillEnterForeground and save the time there, along with invalidating your NSTimer and restarting it.
I am working on a app with 300 images(no text) and trying to change the language with button click and without restarting.
- (IBAction)changeArab:(id)sender {
NSArray* languages = [NSArray arrayWithObjects:#"en", #"fr", nil];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:#"AppleLanguages"];
}
I am able to change the language when i am restarting the app with the code above.
I localized all the images with the required language, is there anyway where i can reload the view once the language is change or change the app one the fly.
Yes, you can change it without restarting app.
You have to use NSNotificationCenter.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(localeChanged:)
name:NSCurrentLocaleDidChangeNotification
object:nil];
}
- (void)localeChanged:(NSNotification *)notif
{
// the user changed the locale
//code to update views or data set.
}
If you have not localized your app in that way. Then Add Custom Observer to Notification Center and when user change language in your custom settings view then it will generate local notification which will be captured by application did receive notification and from that you can load all your view's again.
What is the best way to track App usage time and time a user spends viewing a Screen (or interacting with a UIView) for use within the App itself? Google Analytics seems to do a wonderful job, but the numbers I want to use inside the App itself to unlock items and areas of the App.
You could probably roll your own solution based on Core Data, or if your data is small you could even think of using NSDefaults.
Here's a good start. It involves having a base view controller which you should inherit from in each view controller you want to measure the time spent:
#interface BaseViewController : UIViewController
- (NSString *)screenKey;
+ (NSInteger)secondsInScreen:(NSString *)screenKey;
#end
The implementation simply measures the seconds between the appearance of the screen until it disappears. It's very important to notice the appDidEnterForeground and appDidEnterBackground notifications. When you send your app to the background or it comes back to the foreground, viewDidAppear and viewDidDisappear are not called.
#import "BaseViewController.h"
#implementation BaseViewController {
NSDate *_startDate;
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(appDidEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self startMeasuring];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self stopMeasuring];
}
- (void)appDidEnterBackground:(NSNotification *)not {
[self stopMeasuring];
}
- (void)appDidEnterForeground:(NSNotification *)not {
[self startMeasuring];
}
- (void)startMeasuring {
_startDate = [NSDate date];
}
- (void)stopMeasuring {
NSInteger secondsInScreen = ABS([_startDate timeIntervalSinceNow]);
[self addSecondsToScreen:secondsInScreen];
}
- (NSString *)screenKey {
// Subclasses must override this method
return #"";
}
- (void)addSecondsToScreen:(NSInteger)seconds {
NSString *key = [self screenKey];
if (key.length > 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *s = [defaults objectForKey:key];
NSInteger addedSeconds = s.integerValue + seconds;
[defaults setObject:[NSNumber numberWithInteger:addedSeconds] forKey:[self screenKey]];
[defaults synchronize];
}
}
+ (NSInteger)secondsInScreen:(NSString *)screenKey {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *s = [defaults objectForKey:screenKey];
return s.integerValue;
}
#end
Your subclasses must override screenKey retuning a unique identifier for each screen you want to measure. There's a static method in BaseViewController that allows you to get the sum of seconds spent in each screen.
This is a simple way of doing it. From a design point of view, it would be better to store this information in Core Data and to separate the view controller logic from the storage of that data (the static method secondsInScreen should probably be in another class). But it's a good, working start.
I think you would like to get app usage time to enable new features in the app or give some gifts for your users right?
To reach this, don't use any SDK to track audience like Google Analytics and Flurry for example. Both are for a different purpose you want to do.
A very very simple approach is to store locally using NSUserDefaults the session time of some user, or you can store more detailed information about this using CoreData or SQLite.
The iOS provide a lot of options to you do that, for example, each time the user start the session or open some screen, you can store some NSDate or mach_abosulte_time to save the time of user started the session/screen and you can get the offset time when the app goes to background or when the user closes the screen.
And if you want to store this remotely (server), you can create a service to send this time while the app is visible.
I hope this first insight can help you.
If that isn't possible, then how may I do it after, say, 3 minutes of app usage? This is going to be used for a Rate Us alert but I would rather the user have some time to actually use the app before it asks for them to rate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)options {
// ...
if ([self plusPlusLaunchCount] == 2) {
[self showRateUsAlert];
}
return YES;
}
- (void)showRateUsAlert {
// show the Rate Us alert view
}
- (NSInteger)plusPlusLaunchCount {
static NSString *Key = #"launchCount";
NSInteger count = 1 + [[NSUserDefaults standardUserDefaults] integerForKey:Key];
[[NSUserDefaults standardUserDefaults] setInteger:count forKey:Key];
return count;
}
Instead of making a "Rate Us" alert yourself, why don't you use third-party libraries? This kind of thing has been done so many times anyway.
This is one of a really good one : iRate
Not exactly answer to your question in the title.
You need to set an NSTimer for the time interval you want to show the alert. When the application launches start the timer and after the interval you set finishes, display the alert.
I would suggest you use DidBecomeActive which is called every time you launch app, and come from background/sleep mode:
You would need to cancel the timer in case user doesn't use app for so long.
- (void)applicationDidBecomeActive:(UIApplication *)application{
// Override point for customization after application launch.
rateUsTimer = [[NSTimer scheduledTimerWithTimeInterval:180
target:self
selector:#selector(showRateUsAlert)
userInfo:nil
repeats:NO] retain];
}
- (void)applicationWillResignActive:(UIApplication *)application{
[rateUsTimer_ invalidate];
[rateUsTimer_ release];
rateUsTimer = nil;
}
- (void)applicationDidEnterBackground:(UIApplication *)application{
[rateUsTimer_ invalidate];
[rateUsTimer_ release];
rateUsTimer = nil;
}
- (void)showRateUsAlert {
//Here you present alert
[rateUsTimer_ release];
rateUsTimer = nil;
}