I'm unable to receive accelerometer data in the background, despite the seemingly correct solution per this question How Nike+ GPS on iPhone receives accelerometer updates in the background?
[_motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init]
withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"perform");
[(id) self setAcceleration:accelerometerData.acceleration];
[self performSelectorOnMainThread:#selector(update) withObject:nil waitUntilDone:NO];
});}];
perform is logged whenever the app is in the foreground, but whenever I exit out to background it stops running. Does anyone have any idea why this might be? I've checked "Location Updates" in Background Modes...
Put this code right in front of that line (after making a member variable called bgTaskID of type UIBackgroundTaskIdentifier):
UIApplication *application = [UIApplication sharedApplication];
__weak __typeof(&*self)weakSelf = self;
self.bgTaskID = [application beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof(&*weakSelf)strongSelf = weakSelf;
NSLog(#"BG TASK EXPIRED!");
if (strongSelf) {
[application endBackgroundTask:strongSelf.bgTaskID];
strongSelf.bgTaskID = UIBackgroundTaskInvalid;
}
}];
It can be done by using CoreMotion framework. You have to import CoreMotion framework, then #import <CoreMotion/CoreMotion.h> in your appdelegate.
Here motionManager is object of CMMotionManager.
xData, yData, zData are double values to store accelerometer data.
if (motionManager ==nil) {
motionManager= [[CMMotionManager alloc]init];
}
[motionManager startAccelerometerUpdates];
[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
xData = accelerometerData.acceleration.x;
yData = accelerometerData.acceleration.y;
zData = accelerometerData.acceleration.z;
}];
You have to do it in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions.
You can then use these value of xData, yData, zData where ever you want by appdelegate object, even in background.
Related
NSURLSession Delegate method
URLSessionDidFinishEventsForBackgroundURLSession is not Calling ?
I already enabled the Background Modes in project capabilities settings.
Here is the code
AppDelegate.h Method
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
#end
AppDelegate.m Method
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundTransferCompletionHandler = completionHandler;
}
ViewController.m Method
- (void)viewDidLoad
{
[super viewDidLoad];
//Urls
[self initializeFileDownloadDataArray];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:#"com.GACDemo"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
}
NSUrlSession Method
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
// Check if all download tasks have been finished.
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = #"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
I'm able to download all the files one by one but After downloading all the files, URLSessionDidFinishEventsForBackgroundURLSession method is not calling .
I have to perform some action method After Downloading all the files only.
These delegate methods won't get called if:
The app is already running when the tasks finish;
The app was terminated by double-tapping on the device's home button and manually killing it; or
If you fail to start a background NSURLSession with the same identifier.
So, the obvious questions are:
How was the app terminated? If not terminated, or if terminated incorrectly (e.g. you manually kill it by double-tapping on the home button), that will prevent these delegate methods from getting called.
Are you seeing handleEventsForBackgroundURLSession called at all?
Are you doing this on a physical device? This behaves differently on the simulator.
Bottom line, there's not enough here to diagnose the precise problem, but these are common reasons why that delegate method might not get called.
You later said:
Actually this is the first time I'm using NSURLSession class. My actual requirement is once the download (all the images) is completed then only I can retrieve the images from document directory and I can show in UICollectionView.
I'm following this tutorial from APPCODA. Here is the link http://appcoda.com/background-transfer-service-ios7
If that's your requirement, then background NSURLSession might be overkill. It's slower than standard NSURLSession, and more complicated. Only use background sessions if you really need large downloads to continue in the background after the app is suspended/terminated.
That tutorial you reference seems like a passable introduction to a pretty complicated topic (though I disagree with the URLSessionDidFinish... implementation, as discussed in comments). I would do something like:
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
// log message so we can see completion in device log; remove this once you're done testing the app
NSLog(#"%s", __FUNCTION__);
// Since you may be testing whether the terminated app is awaken when the
// downloads are done, you might want to post local notification.
// (Otherwise, since you cannot use the debugger, you're just staring
// at the device console hoping you see your log messages.) Local notifications
// are very useful in testing this, so you can see when this method is
// called, even if the app wasn't running. Obviously, you have to register
// for local notifications for this to work.
//
// UILocalNotification *notification = [[UILocalNotification alloc] init];
// notification.fireDate = [NSDate date];
// notification.alertBody = [NSString stringWithFormat:NSLocalizedString(#"Downloads done", nil. nil)];
//
// [[UIApplication sharedApplication] scheduleLocalNotification:notification];
// finally, in `handleEventsForBackgroundURLSession` you presumably
// captured the `completionHandler` (but did not call it). So this
// is where you'd call it on the main queue. I just have a property
// of this class in which I saved the completion handler.
dispatch_async(dispatch_get_main_queue(), ^{
if (self.savedCompletionHandler) {
self.savedCompletionHandler();
self.savedCompletionHandler = nil;
}
});
}
The question in my mind is whether you really want background session at all if you're just downloading images for collection view. I'd only do that if there were so many images (or they were so large) that they couldn't be reasonably downloaded while the app was still running.
For the sake of completeness, I'll share a full demonstration of background downloads below:
// AppDelegate.m
#import "AppDelegate.h"
#import "SessionManager.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
// other app delegate methods implemented here
// handle background task, starting session and saving
// completion handler
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
[SessionManager sharedSession].savedCompletionHandler = completionHandler;
}
#end
And
// SessionManager.h
#import UIKit;
#interface SessionManager : NSObject
#property (nonatomic, copy) void (^savedCompletionHandler)();
+ (instancetype)sharedSession;
- (void)startDownload:(NSURL *)url;
#end
and
// SessionManager.m
#import "SessionManager.h"
#interface SessionManager () <NSURLSessionDownloadDelegate, NSURLSessionDelegate>
#property (nonatomic, strong) NSURLSession *session;
#end
#implementation SessionManager
+ (instancetype)sharedSession {
static id sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (instancetype)init {
self = [super init];
if (self) {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"foo"];
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
}
return self;
}
- (void)startDownload:(NSURL *)url {
[self.session downloadTaskWithURL:url];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(#"%s: %#", __FUNCTION__, downloadTask.originalRequest.URL.lastPathComponent);
NSError *error;
NSURL *documents = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
NSAssert(!error, #"Docs failed %#", error);
NSURL *localPath = [documents URLByAppendingPathComponent:downloadTask.originalRequest.URL.lastPathComponent];
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:localPath error:&error]) {
NSLog(#"move failed: %#", error);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(#"%s: %# %#", __FUNCTION__, error, task.originalRequest.URL.lastPathComponent);
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
NSLog(#"%s", __FUNCTION__);
// UILocalNotification *notification = [[UILocalNotification alloc] init];
// notification.fireDate = [NSDate date];
// notification.alertBody = [NSString stringWithFormat:NSLocalizedString(#"Downloads done", nil. nil)];
//
// [[UIApplication sharedApplication] scheduleLocalNotification:notification];
if (self.savedCompletionHandler) {
self.savedCompletionHandler();
self.savedCompletionHandler = nil;
}
}
#end
And, finally, the view controller code that initiates the request:
// ViewController.m
#import "ViewController.h"
#import "SessionManager.h"
#implementation ViewController
- (IBAction)didTapButton:(id)sender {
NSArray *urlStrings = #[#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/s72-55482.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo10/hires/as10-34-5162.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo-soyuz/apollo-soyuz/hires/s75-33375.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-134-20380.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-140-21497.jpg",
#"http://spaceflight.nasa.gov/gallery/images/apollo/apollo17/hires/as17-148-22727.jpg"];
for (NSString *urlString in urlStrings) {
NSURL *url = [NSURL URLWithString:urlString];
[[SessionManager sharedSession] startDownload:url];
}
// explicitly kill app if you want to test background operation
//
// exit(0);
}
- (void)viewDidLoad {
[super viewDidLoad];
// if you're going to use local notifications, you must request permission
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
#end
As stated by Apple:
If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.
i am uploading multiple files using NSURLSessionUploadTask. I want to run same process in back ground and it works fine for current file. App is not suspended until current file got uploaded successfully. Now, when second files comes to upload, it not start uploading process until i again launch or app became active. Uploading is not falling in between thats good. Is there any way to start next uploading process when first finishes. Second uploading is start also in back ground but that works upto 3 min from app goes in back ground. Here i shows my code:
AppDelegate.h
#property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();
AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application{
__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = backgroundTaskIdentifier;
`enter code here`}];
}
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundTransferCompletionHandler = completionHandler;
NSLog(#"handleEventsForBackgroundURLSession called");
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate2 = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"URLSessionDidFinishEventsForBackgroundURLSession call in app delegate");
[session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSLog(#"uploadTasks: %#",uploadTasks);
if ([uploadTasks count] == 0) {
if (appDelegate2.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate2.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate2.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
NSLog(#"All tasks are finished");
}];
}
}
else{
}
}];
}
UploadView.m
- (NSURLSession *)backgroundSession {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSInteger randomNumber = arc4random() % 1000000;
// NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:#"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession%d",(int)randomNumber]];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[NSString stringWithFormat:#"com.upload.myapp.BackgroundSession%d",(int)randomNumber]];
sessionConfiguration.sessionSendsLaunchEvents = YES;
sessionConfiguration.HTTPMaximumConnectionsPerHost = 1;
// Define the Upload task
[sessionConfiguration setHTTPAdditionalHeaders: #{#"Accept": #"text/html"}];
sessionConfiguration.timeoutIntervalForRequest = 600.0;
// sessionConfiguration.networkServiceType = NSURLNetworkServiceTypeBackground;
// sessionConfiguration.discretionary = YES;
sessionConfiguration.allowsCellularAccess = YES;
session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
});
return session;
}
ViewDidLoad(){
....
self.uploadSession = [self backgroundSession];
....}
-UploadStart(){//here i am calling this function in loop. When first file got uploaded, control comes here for second task and then upload should continue.
self.uploadTask = [self.uploadSession uploadTaskWithRequest:requestUpload fromFile:[NSURL fileURLWithPath:tmpfile]]; // self.uploadTask is an object of NSURLSessionUploadTask
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
NSLog(#"didReceiveData Task: %# upload complete", dataTask);
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) self.uploadTask.response;
if (httpResp.statusCode == 200) {
uploadedFiles++; //an int value
if(uploadedFiles==arrUpload.count){
//all files uploaded here
}
else{
//upload next file from here
}
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
}
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
NSLog(#"URLSessionDidFinishEventsForBackgroundURLSession called");
AppDelegate *appDelegate2 = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (appDelegate2.backgroundTransferCompletionHandler != nil) {
// Copy locally the completion handler.
void(^completionHandler)() = appDelegate2.backgroundTransferCompletionHandler;
// Make nil the backgroundTransferCompletionHandler.
appDelegate2.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// Call the completion handler to tell the system that there are no other background transfers.
completionHandler();
NSLog(#"All tasks are finished");
}];
}
}
Above code is completely working, but having problem of next file is not start to upload in back ground after 3 min of App background mode.
Any help will be appreciate. Thanks in advance... For more explanation contact me.
I'd like to know if the system can wake an application in the background if the CMMotionActivity changes, for example, if the user starts walking/running after sitting, I'd like to be able to execute some code and schedule a local notification.
Is there a way to ask the system to wake my app in the background for that ?
EDIT : By looking at the reference, it doesn't seem to be possible ("[...] and updates are not delivered while your app is suspended."), but maybe is there an other way ?
I solved this creating a background timer and checking for the activity type in the selector called method. Just have a look to the code in case it can be useful for you. I accept suggestions, corrections and advices over this.
#define k_timer_time 10.0f
#property NSTimer *timer;
- (void) createBackGroundTimerToCheckMotion{
// create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
__weak __typeof(self) weakSelf = self;
// and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:k_timer_time target:self selector:#selector(onTick:) userInfo:nil repeats:YES];
weakSelf.timer.tolerance = 5;
[[NSRunLoop currentRunLoop] addTimer:weakSelf.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
}
- (void) onTick:(NStimer*)timer{
if([CMMotionActivityManager isActivityAvailable])
{
__weak __typeof(self) weakSelf = self;
CMMotionActivityManager *cm = [[CMMotionActivityManager alloc] init];
CMPedometer *sc = [[CMPedometer alloc] init];
NSDate *now = [NSDate date];
NSDate *last30Sec = [now dateByAddingTimeInterval:-30];
[cm queryActivityStartingFromDate:last30Sec toDate:now toQueue:[NSOperationQueue mainQueue] withHandler:^(NSArray *activities, NSError *error)
{
[activities enumerateObjectsUsingBlock:^(CMMotionActivity *a, NSUInteger idx, BOOL * _Nonnull stop) {
//Your stuff here
}];
}];
}
else
{
NSLog(#"Error accessing Motion data");
}
}
First of all, I'd like to say that I'm really having a bad time trying to configure and use my SQLite DB in a background thread so that the main thread is not blocked.
After I found a little guide somewhere on the Internet, I've decided to go for the FMDB wrapper.
All the methods related to the DB operations are in the same class and this is where I'm getting errors:
I've set the static variables like this:
static FMDatabaseQueue *_queue;
static NSOperationQueue *_writeQueue;
static NSRecursiveLock *_writeQueueLock;
Then in my init method I have:
- (id)init {
self = [super init];
if (self) {
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return self;
}
And this is the method that gives me the error:
- (void)UpdateTime:(NSString *)idT :(int)userId {
[_writeQueue addOperationWithBlock:^{
[_writeQueueLock lock];
[_queue inDatabase:^(FMDatabase *dbase) {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (![dbase executeUpdate:#"update orari set orario=datetime(orario, '? minutes') where nome=? and dataid>=? and idutente=?"
withArgumentsInArray:#[[NSNumber numberWithFloat:deleg.diff], deleg.nome, [NSNumber numberWithInt:deleg.idMed], [NSNumber numberWithInt: userId]]]) {
NSLog(#"error");
}
}];
[_writeQueueLock unlock];
}];
[_writeQueue addOperationWithBlock:^{
[_writeQueueLock lock];
[_queue inDatabase:^(FMDatabase *dbase) {
AppDelegate *deleg = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (![dbase executeUpdate:#"UPDATE orari SET presa=1 where dataid=? and idutente=?"
withArgumentsInArray:#[[NSNumber numberWithInt:deleg.identific], [NSNumber numberWithInt: userId]]]) {
NSLog(#"error");
}
}];
[_writeQueueLock unlock];
}];
[self AddNotification];
}
These are the errors I'm getting:
*** -[NSRecursiveLock dealloc]: lock (<NSRecursiveLock: 0xc38b350> '(null)') deallocated while still in use
DB Error: 5 "database is locked"
*** -[NSRecursiveLock unlock]: lock (<NSRecursiveLock: 0x13378d20> '(null)') unlocked when not locked
From the guide I've read, I supposed that the access to my DB would have been "serialized", and each update would have been added to a queue and executed one at a time.
As you can see, I have a lot to learn about this topic, so any help would really be appreciated.
As I can See you have not created shared instance or singleton instance of this init call
- (id)init {
self = [super init];
if (self) {
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return self;
}
This should be a singleton call as you will create multiple instance of NSOperationQueue which will make DB vulnurable in a multi-threaded environment, try making it singleton call for your database either using GCD or
static DBManager *sharedInstance = nil;
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
_queue = [FMDatabaseQueue databaseQueueWithPath:[self GetDocumentPath]];
_writeQueue = [NSOperationQueue new];
[_writeQueue setMaxConcurrentOperationCount:1];
_writeQueueLock = [NSRecursiveLock new];
}
return sharedInstance;
}
It might solve your problem and this is first time I am answering here and I am new to the environment so please be little bit forgiving :) Thanks
I have some weird issue in my code that I can't figure out and need some help. I have defined a CMMotionManager in my AppDelegate. In my view controller, I define a property:
#property (nonatomic, retain) CMMotionManager *motionManager;
and then use this code to start the updates:
- (void)startMyMotionDetect
{
motionManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
motionManager.deviceMotionUpdateInterval = 1.0/60.0;
[motionManager startDeviceMotionUpdates];
timer = [NSTimer scheduledTimerWithTimeInterval:20/60 target:self selector:#selector(handleDeviceMotion) userInfo:nil repeats:YES];
}
However, the handleDeviceMotion get called only a few time and then it stops updating the deviceMotion output. I have changed the code to the push style (block code) but in that case the block is not getting executed! A test NSLog comment in the block never gets executed. Here is how that code looks like:
motionManager = [(AppDelegate *)[[UIApplication sharedApplication] delegate] sharedManager];
motionManager.deviceMotionUpdateInterval = 1.0/60.0;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *dMotion, NSError *error)
{
NSLog(#"test 1");
[self performSelectorOnMainThread:#selector(handleDeviceMotion) withObject:nil waitUntilDone:YES];
}];
Here is how the handleDeviceMotion code looks like:
- (void)handleDeviceMotion//:(CMDeviceMotion *)dMotion
{
if ([motionManager isDeviceMotionActive])
{
NSLog(#"test");
}
....}
With the first method, I see "test" printed a few times and then it stops.
I thought by retaining motionManager as a property, I don't have to worry about it being released but it appears that it is getting released somewhere (or do you think something else is going on?).
Many thanks for your help.