2017-02-15 14 views
1

У меня возникла непредвиденная проблема с сбоем в моем приложении, которое я специально пытаюсь отлаживать, потому что это происходит в фоновом режиме в то время, которое определяется системой iOS. У меня есть некоторые капитализированные комментарии к коду, которые показывают, где проблема возвращается. Надеюсь, это ясно.Возможная ошибка удаления объекта, ошибка приложения для фона block_invoke_5

Я считаю, что это связано с освобождением объекта.

  • Я попытался использовать __block перед инициализацией объекта, но это не помогло.
  • Я также попытался отправить строки кода по ошибке в основную очередь, но это не помогло.

Фактическая авария перечислен как AppName: __66- [BackgroundUpdateController initiateBackgroundHealthkitObservers] _block_invoke_5 + 160

Я извиняюсь, если некоторые из кода не подходит стандартное форматирование и соглашения. Я сам преподаю из разных мест и поэтому не имею надлежащего опыта с кодом.

Большое спасибо

#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] < -(3600*18)) && ([lastSleepCheck timeIntervalSinceNow] < -(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 > 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 
+0

'__BLOCK, ИСПОЛЬЗУЕМЫЙ ДЛЯ ПРЕДОТВРАЩЕНИЯ ОБЪЕКТА ТЫ ДЕЙСТВУЕТСЯ? Можете ли вы объяснить свои рассуждения? Я думаю, что это большая неверная интерпретация. – ystack

ответ

0

Приставка __block делает не гарантирует существование объекта для @"CalculatedSleepTime" ключа в sleepObject

Я думаю, что вы неправильно поняли хау __block работы. This будет отличным гидом.

На краткий обзор кода, похоже, [sleepObject valueForKey:@"CalculatedSleepTime"] возвращается nil & без допустимость пустых проверки вы пытаетесь извлечь integerValue

Итак, рассмотрим:

NSMutableDictionary *sleepObject = [savedSleepObjects objectAtIndex:0]; 
id calculatedSleepTime = [sleepObject valueForKey:@"CalculatedSleepTime"]; 

if(calculatedSleepTime){ 
    NSDate *sleepStart = [NSDate dateWithTimeIntervalSinceReferenceDate:[calculatedSleepTime integerValue]]; 
} 

И похоже, что вы также не нуждаетесь в префиксе __block в HKHealthStore *backgroundHealthStore = [[HKHealthStore alloc] init];

+0

Большое спасибо за это, я сделаю некоторое тестирование и вернусь, чтобы отметить ответ в ближайшее время. Cheers –

+0

@SimonEdwardes любое обновление по этому вопросу? Могли ли вы это разрешить? – ystack