ios-手动调用viewWillAppear()时出错(Objective-C) [英] ios - error when calling viewWillAppear() manually (Objective-C)

查看:127
本文介绍了ios-手动调用viewWillAppear()时出错(Objective-C)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在ios应用程序的后台更新核心数据,方法是先删除核心数据,然后再将其重新添加.但是,我需要确定要运行的某些功能,但是当我尝试在后台执行所有操作时,这些功能将永远无法运行,除非我更改页面并返回到该页面.

I'm trying to update core-data in the background of my ios app, I do this by first deleting the core-data and then adding it back. However, I need a certain segue to occur for some functions to run but when I try to do everything in the background these functions never run, unless I change the page and go back to it.

因此,我尝试通过手动调用viewWillAppear()来解决此错误,但出现以下错误.

So I tried to fix this error by calling viewWillAppear() manually but I get the following error.

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x17191c00 of class CardScanView was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x16d99c30> (
<NSKeyValueObservance 0x16dcdf20: Observer: 0x17191c00, Key path: verifyingCard, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x16d5db30>

发生错误的类中的方法:

method in class where error occurs:

- (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){
            CardScanView *card = [[CardScanView alloc] init];

            [[NSNotificationCenter defaultCenter] addObserver:card
                                                     selector:@selector(viewWillAppear:)
                                                         name:@"updated" object:nil];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"updated" object:nil];

                });
        });
}

viewWillAppear和viewDidDissapear在其他类中:

viewWillAppear and viewDidDissapear in other class:

- (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];
}


- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
    // Disconnect the bluetooth peripheral device if it exists
    if(self.discoveredPeripheral != nil){
        [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral];
    }
    // Remove KVO for verifyingCard
    [self removeObserver:self forKeyPath:@"verifyingCard"];
}

是什么导致错误,还有比手动调用viewDidLoad更好的方法来解决此问题吗?谢谢

Whats causing the error, also is there a better way to approach this rather than manually calling viewDidLoad? thanks

推荐答案

  1. 核心数据不是线程安全的.您不能只从任何线程访问任何上下文.您应该将persistentStoreCoordinatorviewContext视为只读,并且只能从主线程读取它.对核心数据的所有更改都应通过performBackgroundTask并使用传递给它的上下文.
  2. 您不能只删除核心数据下的文件并期望它们起作用.首先,在删除文件时,还会有许多其他ManagedObjectContext读取或写入.可以将第二核心数据设置为对某些实体使用外部存储,这些实体将存储在单独的文件中.第三,iOS使用WAL模式进行SQLite日志记录,并且对于任何Core Data持久性存储来说,可能都有(可能很大)日志文件.
  3. 要更新用于核心数据更改的UI,应使用NSFetchedResultsController.确保在核心数据设置中设置persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES.
  4. 不保留任何指向managedObjects的指针.可以在您不知情的情况下将它们从上下文中删除,然后访问它们将导致崩溃.而是使用fetchedResultsController-即使仅用于一个对象.
  1. Core-data is not thread safe. You can't just access any context from any thread. You should treat the viewContext of persistentStoreCoordinator as readonly and ONLY read it from the main thread. All changes to core data should go through performBackgroundTask and use the context that is passed to it.
  2. You can't just delete the files under core-data and expect stuff to work. First there many be other managedObjectContext reading or writing while you are deleting the file. Second core data can be set to use external storage for some entities that will be store in separate files. Third, iOS uses WAL mode for SQLite journalling and there may be (potentially large) journal files sitting around for any Core Data persistent store.
  3. To update the UI for core data change you should use a NSFetchedResultsController. make sure to set persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES in your core data setup.
  4. do not keep any pointers to managedObjects. They can be deleted from the context without you being aware and then accessing them will cause a crash. Instead use a fetchedResultsController - even for just one object.

要删除核心数据中的所有实体,请执行以下操作:

To delete all entities in core data:

[self.persistentContainer performBackgroundTask:^(NSManagedObjectContext * _Nonnull) {
    NSArray* entities = context.persistentStoreCoordinator.managedObjectModel.entities;
    for (NSEntityDescription* entity in entities) {
        NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:entity.name];
        request.predicate = [NSPredicate predicateWithValue:YES];
        request.returnsObjectsAsFaults = YES;
        NSArray* result = [context executeFetchRequest:request error:NULL];
        for (NSManagedObject* i in result) {
            [context deleteObject:i];
        }
    }
    [context save:NULL];
}];

这篇关于ios-手动调用viewWillAppear()时出错(Objective-C)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆