I'm using the following code in iOS 10 but when I run it in iOS 9 it crashes. I don't think NSTimer scheduledTimerWithTimeInterval:repeats:block: supports iOS 9. How can I implement a timer that will work in iOS 8 - 10?
static NSTimer* timer = nil;
- (void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}];
}
-(void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
[timer invalidate];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}
You appear to be using a function introduced in iOS10. Further down the page you linked is a function that was in iOS 2.
https://developer.apple.com/documentation/foundation/nstimer/1408356-timerwithtimeinterval?language=objc
Use that instead.
This fixed it:
static NSTimer* timer = nil;
- (void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(hideStatusBar) userInfo:nil repeats:YES];
}
-(void)hideStatusBar
{
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}
-(void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
[timer invalidate];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
}
Related
I'm trying to build an iOS where I can update my location every x seconds and send a notification to update the UI.
I get my location but the update is random. Any ideas how to add the interval ?
here is my code :
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
[self sendNotification :#"long"
:[NSString stringWithFormat:#"%.8f",location.coordinate.longitude]];
[self sendNotification :#"lat"
:[NSString stringWithFormat:#"%.8f",location.coordinate.latitude]];
}
Try this :
declared in .h file
#property (strong, nonatomic) NSDate *lastTimestamp;
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *mostRecentLocation = locations.lastObject;
NSLog(#"Current location: %# %#", #(mostRecentLocation.coordinate.latitude), #(mostRecentLocation.coordinate.longitude));
NSDate *now = [NSDate date];
NSTimeInterval interval = self.lastTimestamp ? [now timeIntervalSinceDate:self.lastTimestamp] : 0;
if (!self.lastTimestamp || interval >= 5 * 60)
{
self.lastTimestamp = now;
NSLog(#"update your UI");
}
}
use NSTimer:
//declare global
NSTimer *ShareTimeCheck;
int ShareSecLeft;
implement this method:
-(void)shareTimeChecking{
if (ShareSecLeft==0) {
[ShareTimeCheck invalidate];
ShareTimeCheck=nil;
}else{
ShareSecLeft--;
if (ShareSecLeft==0) {
[ShareTimeCheck invalidate];
ShareTimeCheck=nil;
}
}
}
call this one in ur location update method:
if (ShareSecLeft==0) {
[ShareTimeCheck invalidate];
ShareTimeCheck=nil;
ShareSecLeft=5;
heduledTimerWithTimeInterval:1 target:self selector:#selector(shareTimeChecking) userInfo:nil repeats:YES];
//write ur code to update the ui. or update to server as per ur requirement.
}
In iOS natively we can’t change the interval at which the system updates the user location. IOS updates position regularly every second, if have GPS signal.
If the application is in the foreground, we could simply stop monitoring and again start it after interval, for example using NSTimer. In this case, we have to think about the life of the application. The application runs in the background and during idle stops working.
My final procedure is use NSTimer in the background by using UIApplication:beginBackgroundTaskWithExpirationHandler:. This timer triggers periodically while the application runs in the background. You can view the following example:
#import "AppDelegate.h"
#implementation AppDelegate
BOOL locationStarted = FALSE;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//set default value after application starts
locationStarted = FALSE;
//create CLLocationManager variable
locationManager = [[CLLocationManager alloc] init];
//set delegate
locationManager.delegate = self;
app = [UIApplication sharedApplication];
return YES;
}
//update location
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"Location: %f, %f", newLocation.coordinates.longtitude, newLocation.coordinates.latitude);
}
//run background task
-(void)runBackgroundTask: (int) time{
//check if application is in background mode
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
//create UIBackgroundTaskIdentifier and create a background task, which starts after time
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:#selector(startTrackingBg) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
}
//starts when application switches to background
- (void)applicationDidEnterBackground:(UIApplication *)application
{
//check if application status is in background
if ( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
NSLog(#"start background tracking from appdelegate");
//start updating location with location manager
[locationManager startUpdatingLocation];
}
//change locationManager status after time
[self runBackgroundTask:20];
}
//starts with background task
-(void)startTrackingBg{
//write background time remaining
NSLog(#"backgroundTimeRemaining: %.0f", [[UIApplication sharedApplication] backgroundTimeRemaining]);
//set default time
int time = 60;
//if locationManager is ON
if (locationStarted == TRUE ) {
//stop update location
[locationManager stopUpdatingLocation];
locationStarted = FALSE;
}else{
//start updating location
[locationManager startUpdatingLocation];
locationStarted = TRUE;
//ime how long the application will update your location
time = 5;
}
[self runBackgroundTask:time];
}
//application switches back from background
- (void)applicationWillEnterForeground:(UIApplication *)application
{
locationStarted = FALSE;
//stop updating
[locationManager stopUpdatingLocation];
}
/*** other methods ***/
- (void)applicationWillResignActive:(UIApplication *)application{}
- (void)applicationDidBecomeActive:(UIApplication *)application{}
- (void)applicationWillTerminate:(UIApplication *)application{}
#end
A simpler solution might be to run the timer loop:
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:#selector(startTrackingBg) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
I have UIView with button Start, UILabel with my NSTimer time and UITableView with time record.
Problem is when I scroll my tableview - NSTimer freeze, why I can do to they work async?
My code:
- (IBAction)startTimer {
_startButton.hidden = YES;
_stopButton.hidden = NO;
isRun = YES;
UIBackgroundTaskIdentifier bgTask = UIBackgroundTaskInvalid;
UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
}];
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01f
target:self
selector:#selector(tick)
userInfo:nil
repeats:YES];
}
- (void)tick {
_timeSot++;
sot++;
/*some code*/
myTime = [NSString stringWithFormat:#"%#:%#:%#", minStr, secStr, sotStr];
[_timeLabel setText:myTime];
}
Add myTimer to NSRunLoopCommonModes:
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01f
target:self
selector:#selector(tick)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];
timer = [NSTimer bk_timerWithTimeInterval:60 block:^(NSTimer *timer) { ....} repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
+ (id)bk_timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(NSTimer *timer))block repeats:(BOOL)inRepeats
{
NSParameterAssert(block != nil);
return [self timerWithTimeInterval:inTimeInterval target:self selector:#selector(bk_executeBlockFromTimer:) userInfo:[block copy] repeats:inRepeats];
}
+ (void)bk_executeBlockFromTimer:(NSTimer *)aTimer {
void (^block)(NSTimer *) = [aTimer userInfo];
if (block) block(aTimer);
}
If I fold and unfold application after a few minutes, almost always the timer is firing immediately and sometimes it fire with delay.
Why the timer does not always work immediately?
try to add this in "didFinishLaunchingWithOptions" in your Appdelegate
__block UIBackgroundTaskIdentifier locationUpdater =[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:locationUpdater];
locationUpdater=UIBackgroundTaskInvalid;
} ];
When i upload to app store, i have this problems
non-public classes: NSCalendarDate, NSTask
But i only use NSTimer to make my own stopwatch
This i my source code
self.timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(stopWatch)
userInfo:nil
repeats:YES] ;
My "Pause" method
pauseStart = [NSDate dateWithTimeIntervalSinceNow:0];
previousFireDate = [self.timer fireDate];
[self.timer setFireDate:[NSDate distantFuture]];
My "Resume" method
float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[self.timer setFireDate:[NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate]];
i also have NSTimer in my AppDelegate
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.delayTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(stopWatch)
userInfo:nil
repeats:YES];
I run in ios6
Could you please show me the root cause?
Thanks you so much
I must to remove mogenerator (https://github.com/rentzsch/mogenerator) library to resolve this problems
I don't know why this project use those private APIs
Hello everyone I need to call a method when the app is in background. This is now i am trying to achieve this but the timer is never called.
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UIApplication* app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do the work associated with the task.
self.timer = nil;
[self initTimer];
});
}
- (void)initTimer {
DebugLog(#"timer INIT!!!!!");
if (self.timer == nil) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.3
target:self
selector:#selector(checkUpdates:)
userInfo:nil
repeats:YES];
}
}
- (void)checkUpdates:(NSTimer *)timer{
[UIApplication sharedApplication].applicationIconBadgeNumber++;
DebugLog(#"timer FIRED!!!!!");
[self initTimer];
}
I need to call the method checkUpdates every Nth minute or seconds while the app is in background.Please note that initTimer is called when the app enters background but the timer is never called.
Apple will not allow the use the application in background if you want to use the application in background you have to use the 'UIBackgroundModes'.
and after that from Appdeligate you can manage this thread
you should check
http://developer.apple.com/library/ios/#documentation/General/Reference/InfoPlistKeyReference/Articles/iPhoneOSKeys.html
hope this will help you