title: Possible Object Deallocation Error, Background App Crash block_invoke_5
body: <p>I am having an unexpected issue with a crash on my app which I am specifically struggling to debug because it occurs in background at a time determined by the iOS system. I have some capitalised comments to the code which show where the issue is being back traced to. I hope this is clear.</p>
  
  <p>I believe it has to do with object deallocation. </p>
  
  <ul>
  <li>I have tried using the __block before initialising the object but
  this has not helped. </li>
  <li>I have also tried dispatching the lines of code
  in error to the main queue but that has not helped.</li>
  </ul>
  
  <p>The actual crash is listed as AppName: __66-[BackgroundUpdateController initiateBackgroundHealthkitObservers]_block_invoke_5 + 160</p>
  
  <p>I apologise if some of the code does not fit standard formatting and conventions. I am self taught from a variety of places and so do not have proper experience with code format.</p>
  
  <p>Many Thanks</p>
  
  <pre><code>#import "BackgroundUpdateController.h"
  NSUserDefaults *backgroundDefaults;
  @implementation BackgroundUpdateController
  
  -(id)init{
  backgroundDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.HeartAnalyzer"];
  return [super init];
  }
  
  -(void)initiateBackgroundHealthkitObservers{
  // Check we should be running here
  if(([backgroundDefaults integerForKey:@"sleepAnalysisEnabled"] != 1) || (![backgroundDefaults boolForKey:@"AutomaticSleepAdd"])) return;
  // Initiate some variables, Use __block to ensure the backgroundHealthStore object does not get deallocated
  __block HKHealthStore *backgroundHealthStore = [[HKHealthStore alloc] init];
  HKQuantityType *activeEnergy = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
  // Enable background delivery of active energy data from HealthKit
  [backgroundHealthStore enableBackgroundDeliveryForType:activeEnergy frequency:HKUpdateFrequencyHourly withCompletion:^(BOOL success, NSError *error) {
  }];
  // Now setup an HKOberverQuery which triggers hourly if there are new active energy data points in HealthKit
  HKObserverQuery *query = [[HKObserverQuery alloc] initWithSampleType:activeEnergy predicate:nil updateHandler:^(HKObserverQuery *query, HKObserverQueryCompletionHandler completionHandler, NSError *error) {
      UIApplicationState state = [[UIApplication sharedApplication] applicationState];
      if (state == UIApplicationStateBackground || state == UIApplicationStateInactive){// Only run when app is not in foreground
          // Load some more variables with checks to ensure they are valid objects
          NSDate *previousSavedDate = [backgroundDefaults objectForKey:@"DateBackgroundSleepLastSaved"];
          if(previousSavedDate == nil) previousSavedDate = [NSDate distantPast];
          NSDate *lastSleepCheck = [backgroundDefaults objectForKey:@"LastSleepCheck"];
          if(lastSleepCheck == nil) lastSleepCheck = [NSDate distantPast];
          // If the last save date was long enough ago and the last sleep check was long enough ago, proceed
          if(([previousSavedDate timeIntervalSinceNow] &lt; -(3600*18)) &amp;&amp; ([lastSleepCheck timeIntervalSinceNow] &lt; -(3600*2))){
              [backgroundDefaults setObject:[NSDate date] forKey:@"LastSleepCheck"];
              [backgroundDefaults setBool:NO forKey:@"BackgroundSleepFound"];
              SleepTimesCalculator *sleepClass = [[SleepTimesCalculator alloc] init];
              [sleepClass calculateSleepTimes:^{
                  NSLog(@"Background sleep time calculations complete");
                  if([backgroundDefaults boolForKey:@"BackgroundSleepFound"]){// Only continue is a sleep time was found
                      __block NSMutableArray *savedSleepObjects = [backgroundDefaults valueForKey:@"SleepTimesDataBase"];
                      if(savedSleepObjects.count &gt; 0){
                              __block NSMutableDictionary *sleepObject = [savedSleepObjects objectAtIndex:0]; // THE __BLOCK USED TO PREVENT THE OBJECT BEING DEALLOCATED, STILL SEEMS TO BE BASED ON THE CRASH
                              NSDate *sleepStart = [NSDate dateWithTimeIntervalSinceReferenceDate:[[sleepObject valueForKey:@"CalculatedSleepTime"]integerValue]];// Get the sleep time start date object
                              NSDate *sleepEnd = [NSDate dateWithTimeIntervalSinceReferenceDate:[[sleepObject valueForKey:@"CalculatedWakeTime"]integerValue]];
                              NSInteger sleepSavedToHealth = [[sleepObject valueForKey:@"SavedToHealth"] integerValue];// Check its not already been saved by some other element of the app
                              if(sleepSavedToHealth != 1){
                                  HKCategorySample *sleepSample = [HKCategorySample categorySampleWithType:[HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis] value:1 startDate:sleepStart endDate:sleepEnd];// Generate sleep object for HealthKit
                                  [backgroundHealthStore saveObject:sleepSample withCompletion:^(BOOL success, NSError *error) {
                                      if (!success) NSLog(@"Uncommon Error! saveObject:sleepSample");
                                      else{
                                          dispatch_async(dispatch_get_main_queue(), ^{// DISPATCH TO MAIN QUEUE AN ATTEMPTED FIX FOR CRASH
                                              sleepObject = [savedSleepObjects objectAtIndex:0];// Choose the most recent sleep time to save
                                              [sleepObject setValue:[NSNumber numberWithInteger:1] forKey:@"SavedToHealth"];// THIS IS WHERE THE 'Last Exception Backtrace (0)' ENDS UP
                                              [savedSleepObjects replaceObjectAtIndex:0 withObject:sleepObject];// Replace the object which now has the 'Saved' tag
                                              [backgroundDefaults setObject:[NSDate date] forKey:@"DateBackgroundSleepLastSaved"];// Save the data of the last time we reached this point
                                              [backgroundDefaults setObject:savedSleepObjects forKey:@"SleepTimesDataBase"];// Save the sleep times back to the database
                                          });
                                      }
                                  }];
                              }
                          completionHandler();// Call the completion handler as we've been throught the sleepObjects array
                      }
                      else completionHandler();// Call the completion handler anyway
                  }
                  else completionHandler();// Call the completion handler anyway
              }];
  
          }
          else completionHandler();
      }
  }];
  [backgroundHealthStore executeQuery:query];// Execute the HealthKit healthstore query
  }
  
  @end
  </code></pre>