[英]ios - error when calling viewWillAppear() manually (Objective-C)
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. 我正在尝试在ios应用程序的后台更新核心数据,方法是先删除核心数据,然后再添加回去。 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.
但是,我需要确定要运行的某些功能,但是当我尝试在后台执行所有操作时,这些功能将永远无法运行,除非我更改页面并返回到该页面。
So I tried to fix this error by calling viewWillAppear() manually but I get the following error. 因此,我尝试通过手动调用viewWillAppear()来修复此错误,但出现以下错误。
*** 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 and viewDidDissapear in other class: 其他类中的viewWillAppear和viewDidDissapear:
- (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"];
}
Whats causing the error, also is there a better way to approach this rather than manually calling viewDidLoad? 是什么引起错误,还有比手动调用viewDidLoad更好的方法来解决此问题吗? thanks
谢谢
viewContext
of persistentStoreCoordinator
as readonly and ONLY read it from the main thread. persistentStoreCoordinator
的viewContext
视为只读,并且只能从主线程读取它。 All changes to core data should go through performBackgroundTask
and use the context that is passed to it. performBackgroundTask
并使用传递给它的上下文。 persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES
in your core data setup. persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES
。 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];
}];
You should never call the viewDidLoad
, viewWillAppear
, etc methods yourself. 您永远不要自己调用
viewDidLoad
, viewWillAppear
等方法。 Only when you override those methods you should call them on super
. 仅当您覆盖这些方法时,才应在
super
上调用它们。
Extract the code you are running to update (which looks like you already have in loadStudents
) and call that method instead of viewWillAppear
. 提取您要更新的代码(看起来就像您已经在
loadStudents
),然后调用该方法而不是viewWillAppear
。
See https://developer.apple.com/documentation/uikit/uiviewcontroller 参见https://developer.apple.com/documentation/uikit/uiviewcontroller
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.