corebluetooth : didDisconnectPeripheral reduce timeout - iphone

I am working with core bluetooth framework . I have implemented the didDisconnectPeripheral method to detect the disconnected peripheral . Right now it is calling around 20 seconds after peripheral has been disconnected . I want to reduce that timeout period . I have searched a lot in the document but not able to get the answer . is it really possible ?

I've been using that method, and it calls (nearly) immediately upon disconnection for me, so it definitely should be possible to reduce that delay period. Are you sure you're not confusing that with the didFailToConnectToPeripheral method? The didFail method normally takes a long time to be called, because I believe I recall reading that Bluetooth LE doesn't have a timeout period, so it will try to connect for a long time.

It is possible that you have the delegate working on a background thread, which could explain the delay.
Check your initialization to see if it is going on the a different thread. If your queue value is something other than nil, that is likely the case.
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
Also, in your didDisconnectPeripheral method, you can place this to determine if the thread changed when it was called.
NSLog(#"Current thread: %#",[NSThread currentThread]);
If the thread has changed, then you can modify the initialization to make sure it goes on the main.

Related

AVAudioSession sharedInstance requestRecordPermission:^(BOOL granted)

Here is my code:
-(void) recordButton{
[[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
NSLog(#"value of the grant is :: %hhd", granted);
if (granted)
{
// perform operation recording
// perfrom some operation on UI(changing labels and all)
}
else
{
// do operation
}
}];
}
Problem is, when i run my app for the first time , after reset in the privacy and my app calls the above defined method, it creates trouble.
when My app run for the first time, allow/disallow microphones messgae(OS defined) method pops up.
when i click allow it displays the boolean(granted correclty). Goes inside IF correctly. Starts the recording correctly. but the UI freezes. and the second part of IF i.e changing label names, doesnt execute till , a timer (added by me stops the method and recording) executes.
PLease help.
I can sense that my 2nd part of the IF(changing UI label are not working in foreground), i.e. background work is working perfectly. Please Help, I am not expert. started iOS programing 2 months back.
I got the answer. my problem was, that when program reached If(granted) ,
it was performing the recording function but didn't performed on UI(changing labels and all).
The problem was, that the whole code was treated as a separate thread and was performed in background.
That's why recording was working properly(as it was a background process).
But UI(changing the labels) was a foreground task.
So For that, I had to execute the UI CODE under a thread that was on MAIN queue. And now it works perfectly.
AVAudioSession's requestRecordPermission callback is a background thread. Using code on the main thread inside a background thread causes issues (and most likely a crash).
You should call a method on the main thread to execute any post granted code. Using performSelectorOnMainThread: is an excellent way to make sure your code is running on the main thread (as explained here: execution on main thread).

CLLocationManager stops in background

I have an app which uses CLLocationManager to track the user's route, drawing dots along the path taken. The app runs in the background using Required background modes > App registers for location updates.
As I understand, anything that happens in the background needs to be called from locationManager:didUpdateToLocation:fromLocation as this is the method that gets called with each location update.
The problem I'm having is that sometimes this stops getting called. It seems to happen when the user's location does not change much within the space of maybe 15 minutes or so. As far as I can tell, calls to locationManager:didUpdateToLocation:fromLocation just stop, presumably to save the battery. Unfortunately, it doesn't resume again when you're back on the move.
I presume there's no way to override this behaviour, so I would like to use Notification Centre to inform the user that the app is no longer recording the route. The problem is, how can the app know that this has happened? If locationManager:didUpdateToLocation:fromLocation is not called, I can't fire my notification. If it is being called, the notification should not fire.
I don't think that there is any way to be notified that the location manager has stopped sending you events, but there is a way to prevent it from happening. In iOS 6, a new feature was added that allows the location manager to power down services if it doesn't think they are being used. If you do the following, the location manager will continue sending you events in the background until you run out of battery:
if ([self.locationManager respondsToSelector:#selector(pausesLocationUpdatesAutomatically)])
{
self.locationManager.pausesLocationUpdatesAutomatically = NO;
}
Also, in iOS6, you should be using locationManager:didUpdateLocations: as locationManager:didUpdateToLocation:fromLocation: is deprecated.
The 2 delegate methods:
-(void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager
and
-(void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager
tells you when the location updates stop and start due to pausing.

CLLocationManager sometimes stops updating while app is in background

I have an app which uses CLLocationManager to track the user's route, drawing dots along the path taken. The app runs in the background using Required background modes > App registers for location updates.
As I understand, anything that happens in the background needs to be called from locationManager:didUpdateToLocation:fromLocation as this is the method that gets called with each location update.
The problem I'm having is that sometimes this stops getting called. It seems to happen when the user's location does not change much within the space of maybe 15 minutes or so. As far as I can tell, calls to locationManager:didUpdateToLocation:fromLocation just stop, presumably to save the battery. Unfortunately, it doesn't resume again when you're back on the move.
I presume there's no way to override this behaviour, so I would like to use Notification Centre to inform the user that the app is no longer recording the route. The problem is, how can the app know that this has happened? If locationManager:didUpdateToLocation:fromLocation is not called, I can't fire my notification. If it is being called, the notification should not fire.
Is there some kind of system notification that says location updates will cease?
I'm finding it quite hard to debug this as I can't take my Mac everywhere when I'm out and about testing the location on the device (there's only so much you can do in the simulator). Any tips for debugging would also be much appreciated!
If you haven't found the answer, I think it is because of a new attribute added to CLLocationManager called pausesLocationUpdatesAutomatically. The attribute defaults to YES, and its behaviour is exactly as you describe. Try setting it to NO and I think it will fix your problem.
Starting in iOS9, make sure you're also setting this property on your location manager:
[locationManager setAllowsBackgroundLocationUpdates:YES]
There's a delegate for location update did Fail
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
There are a few kinds of errors: kCLErrorDenied kCLErrorNetwork Add code here to handle them in the delegate method above not updating location, perhaps a UIAlertView to tell the user.
Personally, I call [locationManager stopUpdatingLocation]; on any error then restart it with an error message depending on the reason for the failure.
ALSO re background, check code in your appDelegate:
- (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.
[self saveContext];
if ([CLLocationManager significantLocationChangeMonitoringAvailable]) {
// Stop normal location updates and start significant location change updates for battery efficiency.
[self.locationHandler.locationManager stopUpdatingLocation];
[self.locationHandler.locationManager startMonitoringSignificantLocationChanges];
}
else {
NSLog(#"Significant location change monitoring is not available.");
}
}
LASTLY re: testing. You can simulate some errors in location by changing the location movement in the simulator. For example, going from running to driving will cause an error. Going from running to a single specific custom location will cause an error. They should all appear in the delegate method for locationManager above.
I've managed to solve the problem by adding a local notification that fires with a 90 second delay every time a new location is added to the route. When the next location is added, the previous notification is cancelled and a new one is scheduled. This way, if it stops updating, a notification is received by the user (albeit with a 90 second delay). It's not ideal, and it may not be great for battery life, but it is a solution and it's the best I've got for the time being.
#Ron, I meet the same problem as beev describe, and i had already set pausesLocationUpdatesAutomatically to NO. I think because iOS will kill some apps that didn't be triggered in 10 minutes when it's under background. So add local notification maybe a good choice at the moment.

How to trigger a delegate method after a certain period of time?

I'm using a class which downloads a file asynchronously .. works a bit like this
// in AViewController.m
DataGetter *blueFile = [[DataGetter alloc] init];
blueFile.delegate = self;
[blueFile getData:#"http://example.com/blue-file"];
It has a delegate method which does stuff to the file once downloaded
- (void) dataGetterFinished:(DataGetter *)dataGetter
{
// code
}
This works OK in ideal conditions, but as we're dealing with a mobile device, connections are not always reliable. The connection might break off half way thru, or it might be unusably slow.
So I'm wondering how I would set up a delegate method which triggers after, say, 10 seconds, which then displays an error and stops the operation. Would I have to use NSTimer, or NSNotification , or some combination?
Quinn "The Eskimo!" from Apple did a two talks on network programming for iPhone at WWDC 2010. It's session 207 and 208, you can download them here: http://developer.apple.com/videos/wwdc/2010/
The simple recepie for network success is:
Use NSURLConnection asynchronously.
Do not set a manual time-out using timers or any other means, the defaults are sane.
Instead be prepared to handle for a connection:didFailWithError:, that will be sent for time-outs.
If needed you can manually cancel a connection using -[NSURLConnection cancel], in response to user action for example.

Iphone app is delayed for 10 -15 minutes when iphone is in sleep mode

I have created an app that uses NSTimer, which gets triggered each second.
My problem is that if the Iphone is in sleep mode i get a delay for 10 to 15
minutes before the event is triggered. I have stackoverflowed and googled this
and the reason for this seems to be that the phone stops listening for certain
events when in sleep mode.
Some people have solved this issue by playing a mute sound, not allowing the
phone to sleep.
What could be the reason for the delay?
The mute sound solution seems to be a very "dirty" one. Is there some other way to solve this?
If I use the mute sound solution will it the pass the apple review?
Code:
timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:#selector(goAction)userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void)goAction {
// Here i check for some dates and then call the activateBeepAlarmView
}
Well since no one has answered my three questions I will have to answer them:
1. What could be the reason for the delay?
I will have to quote Ben S:
Once applicationWillResignActive gets called on your application you simply stop receiving events:
The delegate can implement this method to make adjustments when the application transitions from an active state to an inactive state. When an application is inactive, it is executing but is not dispatching incoming events. This occurs when an overlay window pops up or when the device is locked.
The point of sleep mode is to save energy. To do so, the device stops listening for events like the ones you're asking for. NSTimer events will still fire since they don't require expensive (battery-wise) hardware monitoring. Also, alarms are implemented using NSTimer, so they need to be able to function even when in sleep. Otherwise, people might not wake up and blame their iPhone.
2. The mute sound solution seems to be a very "dirty" one. Is there some other way to solve this?
No, currently I haven't found another solution, please feel free to correct me if I'm wrong.
Check out this blog post how to do it.
3. If I use the mute sound solution will it the pass the apple review?
Yes
When the iPhone goes to sleep, so does your app and the runloop that runs the NSTimer.
You seem to think that an NSTimer is some sort of hardware based timer. It is not. It operates completely within the software of the app that launches it. I don't know what is waking your app up but it is definitely not the NSTimer.
In short, what you want to do is impossible. You can't sleep the phone and then have an app still active and running. The mute sound technique is just a kludge to keep the phone awake and the app running.
If you need the phone to stay awake, you need to set the application's idleTimerDisabled to YES. This will prevent the phone from sleeping and the app can remain active. But once you let the phone sleep, it cannot be awaken from app code. Only the hardware can do that in response to an alarm or an incoming message.
What happens in your app when the NSTimer is triggered each second? Please provide code showing the creation of the timer as well as the code for the selector that is called when the timer completes.
Also what do you mean by a "delay for 10 to 15 minutes"? Is the delay always that long or is that how long you wait to awaken the iPhone and then the event is triggered?
Depending on what you need to do every second you can handle this situation in different ways. Please respond and we'll try to work our way through this.
Bart
#Jakob,
This is impossible with the "Official SDK". If you're developing apps for jail broken phone, then you can use IOKit framework for this. For more info please refer this.