无需更改屏幕即可更新核心数据

时间:2017-06-14 18:53:35

标签: ios objective-c multithreading core-data

在我更新我的核心数据存储后 - 通过删除然后添加数据 - 在另一个线程中,我需要更改屏幕然后返回数据以更新它。有没有办法更新Core Data而无需更改应用程序中的屏幕?

重置数据库的代码:

- (void) resetDatabase {
    count++;

    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
        }
        NSLog(@"*****************************");
        NSLog(@"updating");
        NSLog(@"count: %d", count);
        NSLog(@"*****************************");

        [self populateDatabase:0 con:con];


        NSTimer *timer = [NSTimer timerWithTimeInterval:60.0
                                                 target:self
                                               selector:@selector(resetDatabase)
                                               userInfo:nil repeats:NO];
        [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        dispatch_async(dispatch_get_main_queue(), ^(void){

                });
        });
}

更改ui时运行的代码:

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // Setup KVO for verifyingcard
    [self addObserver:self forKeyPath:@"verifyingCard" options:NSKeyValueObservingOptionNew context:nil];

    if([BluetoothTech isEqualToString:@"BLE"]){
        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey: @YES}];
    }
    else if([BluetoothTech isEqualToString:@"HID"]){
        [self.bluetoothScanTextView becomeFirstResponder];
    }
    [self loadStudents];
}

我认为它与loadStudents()函数有关,但是当我使用NSNotificationCenter从其他类运行它时,它仍然无效。

LoadStudent代码:

- (void)loadStudents{
    NSError *error = nil;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Caf_student_cards"];
    NSArray *arr = [[self.manager managedObjectContext] executeFetchRequest:fetchRequest error:&error];
    for(int i = 0; i < [arr count]; i++){
        if([[[arr objectAtIndex:i] valueForKey:@"user_id"] isEqualToString:@"201509061"]){
            NSLog(@"%@",[arr objectAtIndex:i]);
        }
    }
    if(!error){
        self.caf_student_cards = [NSMutableArray arrayWithArray:arr];
        self.keys = [[[arr.firstObject entity] attributesByName] allKeys];
    }
    else{
        NSLog(@"%s %s %s","\n\n\n",[[error localizedDescription] UTF8String],"\n\n\n");
        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:@"Check connection and relog back into cafeteria." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        });
    }
}

1 个答案:

答案 0 :(得分:2)

此代码存在多个问题。

与您的问题最直接相关的是您正在更新持久性商店,但不更新您的用户界面。它不会自动发生。如果您有新数据,则需要告知UI更新。如何做到这一点取决于您拥有的UI类型。如果它是一个表视图,它可能就像告诉表视图重新加载其数据一样简单。如果你有一个用来保存UI数据的数组,你也需要更新它(看起来这可能是代码中的caf_student_cards但是无法确定。

其他问题 - 这些是您需要立即解决的主要问题:

  1. 你正在做Core Data多线程错误。使用dispatch_async在这里无效。您需要在托管对象上下文中使用performBlockperformBlockAndWait,或者在持久容器上使用performBackgroundTask
  2. 您要删除主持久存储文件,但不删除日记文件。这几乎可以保证可以防止旧数据被删除,或者只是导致数据损坏。你正在做的不是一种有用的技术。删除持久性存储文件很少是个好主意。如果您想要删除现有数据,请将其从Core Data中删除,也可以通过告诉您的上下文delete对象,或者使用NSBatchDeleteRequest
  3. 可能还有其他人。这段代码很乱。如果你花一点时间查看Apple的Core Data Programming Guide,那么你会为自己做一件大事。

    此外,您keep几乎询问了same个问题repeatedly。你有一些很好的建议,但你似乎没有采取任何建议。如果您想了解更多信息,请阅读以前在您发布此问题时已经提供的其他答案。