Application freezes in IOS 10 - objective-c

I have developed a application where it uses GCD timer and Sqlite database it works fine in IOS8 and IOS9 but it fails in IOS10 that it it does not crash but it freezes I am using Xcode 8.1.
The work flow of the application is when i click on the button timer will start running in background and keep on update the label as well as table list data and inserting the same data to the sqlite database.
Here my problem is when i keep on click the button to update the data it works fine until it insert the 50-60 records after it suddenly freezes and block the UI so to check that i have debug the code I came up with the assumption that it fails because it's blocking the thread but I did not find any solution to resolve it please help me out to resolve my problem thanks in advance.
Here is the output from my pause:
Error showing after pause and debug:
On click of button event I am trying to reload the table and displaying records in it as well as inserting the data to the sqlite database and I have a label which shows the timer data in it.
dispatch_async(dispatch_get_main_queue(), ^{
self.lbltimer.text = [NSString stringWithFormat:#"%.4f", Timeinterval];
});
Below is my code how I am using GCD timer which runs continuously:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.aTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(ShowTime:) userInfo:nil repeats:YES];
});

I think you should start the timer on the main thread
by triggering :
-(IBAction)clickEven:(id)sender{
self.aTimer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self selector:#selector(ShowTime:) userInfo:nil repeats:YES];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Sqlite operation
dispatch_async(dispatch_get_main_queue(), ^{
[self.aTimer invalidate];
});
});
}
-(void)ShowTime:(NSTimer*)timer {
self.lbltimer.text = [NSString stringWithFormat:#"%.4f", Timeinterval];
}

Related

How to stop sending requests to dispatch_async requests for ringing?

I click the button to beep and as the background thread there is a welcome message appears on the view controller, the beep is continuously going on until i close the application.
How can i suspend the queue for further execution when welcome message arrives on the view controller?
I tried calling from another view controller dispatch_suspend(dispatch_get_main_queue()); when welcome screen comes in but the beep is continuously going on in background. Can somebody have hint to stop queue from executing or just clean the queue?
dispatch_async(dispatch_get_main_queue(), ^{
NSInteger timeintervalForBeep;
if (_bu.buModel == BuTwo) {
timeintervalForBeep = 7;
} else {
timeintervalForBeep = 2;
}
_findBeepTimer = [NSTimer scheduledTimerWithTimeInterval:timeintervalForBeep
target:self
selector:#selector(makeBeep)
userInfo:nil
repeats:YES];
// Fire it once immediately.
[_findBeepTimer fire];
});
in the makeBeep function, invalidate the timer by adding the following codes:
[_findBeepTimer invalidate];
_findBeepTimer = nil;

NSTimer Will Not Invalidate

-(IBAction) loadWeb: (id) sender {
[_webView loadRequest:nsrequest2];
_webView1.hidden = YES;
_webView.hidden = NO;
self.checkForAdd = [NSTimer scheduledTimerWithTimeInterval:0.4
target:self selector:#selector(checkForAddToCart:) userInfo:nil
repeats:YES];
}
-(IBAction)button1:(id)sender {
[self.checkForAdd invalidate];
}
How would I invalidate the timer? I have tried it without self and many other ways, but for some reason, when I press the button the timer does not invalidate.
Check if loadWeb: is called multiple times. If it is, you will have old timers running without having a reference to them so you can't invalidate them. You should have [self.checkForAdd invalidate]; before you create the new timer.
When you do invalidate the timer, if you aren't creating a new one, set self.checkForAdd = nil; to be sure you aren't going to try using the timer again (some actions will throw an exception if you do).
If at any point you do self.checkForAdd = nil; without having invalidated the timer then you won't have a reference to it so you won't be able to invalidate it in the future.
According to your code, loadWeb is being trigger by a button. So you will be creating new timer every time when button will be press. Its better you create timer on some where else, like create in init, or in viewDidLoad method, because if you are creating this here, you have to make sure you are not creating timer again and again. You can do this by doing a if check
if(!self.checkForAdd){
self.checkForAdd = [NSTimer scheduledTimerWithTimeInterval:0.4
target:self selector:#selector(checkForAddToCart:) userInfo:nil
repeats:YES];
}
Right now its creating new timer on button tap, and previous one have no reference.

NSTimer supposed to be fired from inside a method called by a notification

In my iOS application I have registered the AppDelegate as notification listener for CoreData changes. With this piece of code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mergeChangesFromContextDidSaveNotification:)
name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
object:[self persistentStoreCoordinator]];
And the mergeChangesFromContextDidSaveNotification method get correctly called every time there's an update.
However inside this method I am trying to call an NSTimer for doing another operation:
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification {
NSTimer *t =[NSTimer scheduledTimerWithTimeInterval:10.0
target:self
selector:#selector(mergeCoreDataFromCloud:)
userInfo:nil
repeats:NO];
}
}
and the point is that mergeCoreDataFromCloud: which should be fired by the timer is never called. This is the signature:
-(void)mergeCoreDataFromCloud:(NSTimer*)timer {
// never called...
}
please note that I am at early stage of development, the code is not perfect, and I am only interested in knowing why the timer is not started.
I suppose it has something to do with threads, but I have no guess...
thanks
A timer relies on the run loop being run in the mode(s) in which it has been scheduled.
In a Cocoa app, the main thread runs its run loop automatically. However, no other thread can be relied on to run its run loop automatically.
So, usually you want to schedule timers on the main thread. You can also schedule them on a thread you create and control, which you cause to run its run loop in an appropriate mode.
There's no enough information in your question to know what thread this code is being called on.
You could be right about the thread issue -- it that's the case, then I think you have to use an unscheduled timer and add it to the run loop manually. Try this, and see if it works:
NSTimer *t = [NSTimer timerWithTimeInterval:10 target:self selector:#selector(mergeCoreDataFromCloud:) userInfo:nil repeats:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:t forMode:NSDefaultRunLoopMode];

iOS5 ARC is it safe to schedule NSTimers from background selectors?

I'm trying to debug my application.
I've been using some NSTimer instances in my non-arc code like this (from the main thread):
[NSTimer scheduledTimerWithTimeInterval:5 target:musicPlayer selector:#selector(playPause:) userInfo:nil repeats:NO];
This works fine if I assign this code to a button and click a button. The timer fires.
I've also tried:
if( self.deliveryTimer == nil)
{
self.deliveryTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(playPause:) userInfo:nil repeats:NO];
}
-(void)playPause:(NSTimer*)timer
{
[deliveryTimer invalidate];
deliveryTimer = nil;
//more code here
}
I would expect the timer to execute, hit the play/pause method below, then turn to nil, so I can reset the timer later. The reason why I'm checking for nil is because I have 3 different code paths that may set the timer. Each one has an NSLog statement indicating that the timer has been scheduled.
My code runs, and I see that the timers are being scheduled, but they don't seem to fire in the course of normal app execution. I'm investigating why. Short term timers, using the same logic fire fine. It is when I let the app run for a while that I'm running into issues.
Could the NSTimers be reclaimed by ARC?
Does it matter if I set the timer from a performSelectorInBackground? As I was writing up this question, I noticed that some of my timers were created from a code path that is being called through:
[self performSelectorInBackground:#selector(notifyDelegateOfDataPoint:) withObject:data];
could the background selector be the reason why my timers do not fire/get reclaimed earlier?
Any help is appreciated, this bug has been bugging me for over 2 weeks!
Update: after changing the code to use the main thread for NSTimers, the timers fire correctly, causing the music to play:
[self performSelectorOnMainThread:#selector(deliverReminder:) withObject:nil waitUntilDone:NO];
-(void)deliverReminder:(id)sender{
[ NSTimer scheduledTimerWithTimeInterval:10 target:reminderDeliverySystem selector:#selector(playAfterDelay:) userInfo:nil repeats:NO];
[self postMessageWithTitle:nil message:#"Deliver Reminder Called" action:kNoContextAction];
}
-(void)playAfterDelay:(id)sender
{
int reminderDelay = reminder.delayValue.intValue;
[playTimers addObject:[NSTimer scheduledTimerWithTimeInterval:reminderDelay target:self selector:#selector(appMusicPlayerPlay:) userInfo:nil repeats:NO]];
}
Here I have a whole bunch of timers, which is because I don't know how to pass a primitive to a target with a selector.
An NSTimer requires a run loop to be running in that background thread for it to keep firing. The main thread already has an active run loop, which is why your timers work fine when executed on it.
If you want to use your timers within a background thread, you can do something like the following:
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
self.deliveryTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(playPause:) userInfo:nil repeats:NO];
[runLoop run];
What was probably happening with your short duration timers firing, but the longer ones not, was that they were firing while the thread was still active, but without a run loop to keep it going, were failing after the thread reached the end of its execution.
I don't believe this is ARC-related, although there may be something there you'll have to watch for, because the NSRunLoop holds on to a timer that is attached to it. Following standard procedure with NSTimers should avoid ARC problems.

Update UILabel by timer doesn't work

I have UIView with Label that shows the time like stopwatch. I set the label from a Timer method. Here is the code below:
ivarTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
My update method looks like this:
- (void)updateTimer {
...
self.myLabel.text = #"someChangedStr";
}
It works great. But on the view I have UITableView and If I scroll the TableView, self.myLabel.text stops update. Should I use threads or something else?
You could run your timer on another thread, but you must always do UI updates on the main thread.
However, try adding your NSTimer to the UITrackingRunLoopMode so it will still fire when tracking touches on your window.
[[NSRunLoop mainRunLoop] addTimer:ivarTimer
forMode:UITrackingRunLoopMode];