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