Как обрабатывать случай сбоя загрузки persistentContainer

#ios #objective-c #sqlite #core-data #core

#iOS #objective-c #sqlite #core-данные #Ядро

Вопрос:

Это код, который я использую для создания постоянного контейнера для основного стека данных.

Я хочу обработать случай сбоя, когда persistentContainer не равен нулю и уже загружен в общий класс экземпляра CoredataHandler.

Файл CoredataHandler.h

 @property (strong, nonatomic) NSPersistentContainer *persistentContainer;
@property (nonatomic) BOOL isStoreLoaded;

  

Файл CoredataHandler.m

 @implementation CoredataHandler

 (CoredataHandler *) sharedInstance
{
    static CoredataHandler *shared = nil;
    
    static dispatch_once_t onceToken;
    
    dispatch_once(amp;onceToken, ^{
        
        shared = [[self alloc] init];
        
    });
    
    return shared;
}

- (id)init {
    if (self = [super init]) {
        _persistentContainer = self.persistentContainer;
    }
    return self;
}


@synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        NSURL * storeURL  =  [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        storeURL = [storeURL URLByAppendingPathComponent:@"MyDataBase"];

        if (_persistentContainer == nil) {
            NSPersistentContainer *container = [[NSPersistentContainer alloc] initWithName:@"MyDataBase"];

            NSPersistentStoreDescription * persistentStoreDescription = [[NSPersistentStoreDescription alloc] initWithURL:storeURL];
            persistentStoreDescription.shouldMigrateStoreAutomatically = YES;
            [persistentStoreDescription setOption:NSFileProtectionComplete forKey:NSPersistentStoreFileProtectionKey];
            persistentStoreDescription.shouldInferMappingModelAutomatically = YES;
            container.persistentStoreDescriptions = @[persistentStoreDescription];

            [container loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                     */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    //abort();

                    self->_isStoreLoaded = NO;

                }
                self->_isStoreLoaded = YES;
                return;

            }];

            if (self.isStoreLoaded) {
                _persistentContainer = container;
            }
        }  else {
            if (![self persistentStoreExistsWithStoreURL:storeURL]) {
                _persistentContainer = nil;
            }
        }
    }
    return _persistentContainer;

}
  

Я попытался, проверив, существует ли хранилище в пути

 -(BOOL)persistentStoreExistsWithStoreURL:(NSURL *)url {

    if (url amp;amp;
        url.isFileURL amp;amp;
        [NSFileManager.defaultManager fileExistsAtPath:url.path]) {
        return YES;
    }
    return NO;
}


-(NSBatchUpdateResult *)executeRequestForNSBatchUpdateResult:(NSBatchUpdateRequest *)updateRequest {
    NSBatchUpdateResult *batchUpdateResult = nil;
    if (!self.persistentContainer) {
        return nil;
    }

    if (self.persistentContainer.viewContext) {
        batchUpdateResult = (NSBatchUpdateResult *)[self.persistentContainer.viewContext executeRequest:updateRequest error:nil];
    }
    return batchUpdateResu<
}


@end

  
 -(void)markItmesInCategory:(NSNumber*)categoryId {
    NSBatchUpdateRequest *req= [[NSBatchUpdateRequest alloc] initWithEntityName:@"Items_table"];
    req.predicate = [NSPredicate predicateWithFormat:@"categoryId=%d",[channelKey intValue]];
    req.propertiesToUpdate = @{
        @"status" : @(1)
    };
    req.resultType = NSUpdatedObjectsCountResultType;
    CoredataHandler * dbHandler = [CoredataHandler sharedInstance];

    NSError * fetchError = nil;

    NSBatchUpdateResult *batchUpdateResult = (NSBatchUpdateResult *)[dbHandler executeRequestForNSBatchUpdateResult:req];

    if (batchUpdateResult) {
        NSLog(@"updated rows", batchUpdateResult.result);
    }
}
  

Как справиться со случаем, если его уже загруженный объект находится в общем классе экземпляра и если хранилище имеет некоторые проблемы с разрешениями при доступе

Пример: постоянное хранилище недоступно из-за разрешений или защиты данных, когда устройство заблокировано.

Комментарии:

1. Когда и где в вашем коде вы хотите это проверить? CoredataHandler инициализируется только один раз при обращении к нему, поэтому, когда может возникнуть «случай сбоя, когда persistentContainer не равен нулю и уже загружен в общий класс экземпляра CoredataHandler»?

2. Я хотел проверить в CoredataHandler при доступе к методу persistentContainer в другой части, доступно ли основное хранилище данных или нет, чтобы я мог справиться, если хранилище недоступно, когда телефон заблокирован в случае NSFileProtectionComplete