使用线程和核心数据 (Objective-C) 时出错



制作一个删除核心数据然后在后台添加的方法(以便核心数据可以更新(

(void) resetDatabase {
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        ConDAO *con = [[ConDAO alloc] init];
        DatabaseManager *manager = [DatabaseManager sharedManager];
        NSError * error;
        NSURL * storeURL = [[[manager managedObjectContext] persistentStoreCoordinator] URLForPersistentStore:[[[[manager managedObjectContext] persistentStoreCoordinator] persistentStores] lastObject]];
        [[manager managedObjectContext] reset];//to drop pending changes
        if ([[[manager managedObjectContext] persistentStoreCoordinator] removePersistentStore:[[[[manager managedObjectContext] persistentStoreCoordinator] persistentStores] lastObject] error:&error])
        {
            // remove the file containing the data
            [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
            //recreate the store like in the  appDelegate method
            [[[manager managedObjectContext] persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];//recreates the persistent store
        }
        [self populateDatabase:0 con:con];
        NSLog(@"*****************************");
        NSLog(@"updating");
        NSLog(@"*****************************");
        NSTimer *timer = [NSTimer timerWithTimeInterval:60.0
                                                 target:self
                                               selector:@selector(resetDatabase)
                                               userInfo:nil repeats:YES];
        [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    });
}

但是,在计时器运行并且函数执行几次后,我收到错误

EXC_BAD_ACCESS(code = 1, address = 0x38)

采用以下方法:

- (void)newManagedCaf
{
    cafCards = [[NSManagedObject alloc] initWithEntity:cafDescription insertIntoManagedObjectContext:managedObjectContext];
}

在以下位置调用发生错误的方法:

// First the student database is updated
- (void)populateDatabase:(int)tries con:(ConDAO *)con{
    DatabaseManager *manager = [DatabaseManager sharedManager];
    //Fetch greatest contact number in local database
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Caf_student_cards"];
    fetchRequest.fetchLimit = 1;
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"contact" ascending:NO]];
    NSError *error = nil;
    id cont = [[[manager managedObjectContext] executeFetchRequest:fetchRequest error:&error].firstObject valueForKey:@"contact"];
    int contact = 0;
    if (cont != nil){
        contact = [cont intValue];
    } //Pull students newer than the newest student in the local database
    //NSString *query = [NSString stringWithFormat:@"SELECT caf.user_id, caf.family_number, caf.card_number, caf.suspension_start_date, caf.suspension_end_date, caf.balance, util.room, caf.meal_plan_type, student.special_diet, student.specify_other, users.surname, users.type, users.name, users.contact from(SELECT * from caf_student_cards) AS caf LEFT JOIN (SELECT user_id, special_diet, specify_other FROM students) AS student ON caf.user_id = student.user_id LEFT JOIN (SELECT resource_id AS room, user_id FROM utilizations) AS util ON caf.user_id = util.user_id LEFT JOIN (SELECT surname, name, type, user_id, contact FROM system_users) AS users ON caf.user_id = users.user_id WHERE contact > %d", contact];
    NSString *query = @"GetCaf";
    [con executePreparedSQLAsync:query Parameter:@[[NSString stringWithFormat:@"%d",contact]] withCompletion:^(NSMutableArray *data, NSError *error){
        // Error encountered
        if(error != nil){
            NSLog(@"err: %@", error);
            // Retry up to twice to execute the query
            if(tries < 3){
                [self populateDatabase:(tries+1) con:con];
            }
            else{
                NSLog(@"%s %s %s","nnn",[[error localizedDescription] UTF8String],"nnn");
                dispatch_async(dispatch_get_main_queue(), ^{
                    // Show alert to tell user to reload this page
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"Error: %@", [error localizedDescription]] message:@"No connection, could not update local data." delegate:self cancelButtonTitle:@"Back" otherButtonTitles:@"Continue", nil];
                    [alert show];
                });
            }
        }
        else{
            // If successful, store the results in the local database
            for(NSMutableDictionary *result in data){
                [manager newManagedCaf];
                for (NSString *name in result){
                    if ([name isEqualToString:@"contact"]){
                    NSNumber *num = [NSNumber numberWithInteger:[[result valueForKey:name] integerValue]];
                        [[manager cafCards] setValue:num forKey:name];
                    }
                    else{
                        [[manager cafCards] setValue:[result valueForKey:name] forKey:name];
                    }
                }
                [[manager cafCards] setValue:[NSNumber numberWithBool:YES] forKey:@"synced"];
            }
            [[manager cafCards].managedObjectContext save:&error];
            if(error != nil){
                NSLog(@"Unable to save managed object context.");
                NSLog(@"%@, %@", error, error.localizedDescription);
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"Error: %@", [error localizedDescription]] message:@"Database not working, try again later or inform IT." delegate:self cancelButtonTitle:@"Back" otherButtonTitles:nil, nil];
                [alert show];
            }
            [self getImages:0 con:con withManager:manager];
       }
    }];
}

有时我也会收到以下错误,该错误发生在重置数据库方法中:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'nil is not a valid store.'
看起来

您在删除存储后正在使用持久存储的 managedObjectContext。这是插入时崩溃的原因。BAD_ACCESS正在尝试插入到零存储区。

如果目标是 9+,则可以使用 replacePersistentStoreAtUrl 替换数据存储。

相关问题的链接在这里。

最新更新