核心数据:使用瞬态属性解密并缓存另一个值

时间:2013-11-23 11:13:09

标签: ios objective-c core-data

我在Core Data中创建了一个瞬态属性,它保存非瞬态加密属性formula的解密字符串formulaEnc

我已经定义了一个局部变量NSString *tmpFormula来缓存解密的公式,以避免每次访问托管对象时解密该值。

这是我添加到托管对象的自定义访问者:

- (NSString*)formula
{
    [self willAccessValueForKey:@"formula"];
    NSString *tmpFormula = [self primitiveValueForKey:@"formula"];
    [self didAccessValueForKey:@"formula"];

    [self willAccessValueForKey:@"formulaEnc"];
    NSString *formulaEnc = [self primitiveValueForKey:@"formulaEnc"];
    [self didAccessValueForKey:@"formulaEnc"];

    if(!tmpFormula && formulaEnc) {
        NSLog(@"Decryption started.");
        NSData *encryptedData = [NSData dataFromBase64String:self.formulaEnc];
        NSError *decryptionError;
        NSString *password = @"password";

        NSData *decryptedData = [RNDecryptor 
              decryptData:encryptedData
              withPassword:password
              error:&decryptionError];

        if (decryptionError) NSLog(@"Decryption 
              failed with error: %@",decryptionError);

        NSString *decryptedString = [[NSString alloc] 
                   initWithData:decryptedData encoding:NSUTF8StringEncoding];
        tmpFormula = decryptedString;
        [self setPrimitiveValue:tmpFormula forKey:@"formula"];
    }
    return tmpFormula;
}

我将所有托管对象存储在NSArray中以将其缓存在内存中。但是,即使对象被缓存,每当我读取托管对象时,访问访问者formula(请参阅上面的代码片段)并再次进行解密。

BTW:这就是我在主代码中创建NSArray托管对象的方法:

- (NSArray*)allFigures
{   if (!_allFigures) {
        NSLog(@"Recalculating allFigures.");
        NSFetchRequest *request = [NSFetchRequest 
                fetchRequestWithEntityName:@"Figure"];
        request.sortDescriptors = @[[NSSortDescriptor 
                sortDescriptorWithKey:@"order" ascending:YES ]];
        request.returnsObjectsAsFaults = NO;
        NSError *fetchError;
        NSArray *result = [self.managedDocument.managedObjectContext 
               executeFetchRequest:request error:&fetchError];
        _allFigures = result;
    }
    return _allFigures;
}

这是前一个代码段的调用方式:

NSArray *figures = [self figuresForCategory:category
inManagedObjectContext:self.managedDocument.managedObjectContext];

[self calculateValuesForFigures:figures withCompletion:
    ^(NSDictionary *values, NSArray *figures) {
    dispatch_async(dispatch_get_main_queue(), ^{

       self.figures = figures;
    });
}];

- (NSArray *)figuresForCategory:(NSString*)category 
      inManagedObjectContext:(NSManagedObjectContext*)context
{  
    NSPredicate *predicate = [NSPredicate predicateWithFormat:
            @"xyz CONTAINS[cd] %@ ",category];   
    return [self.allFigures filteredArrayUsingPredicate:predicate];
}

- (void)calculateValuesForFigures:(NSArray*)figures 
        withCompletion:(void(^)(NSDictionary* valueDict, 
        NSArray* figures))completionBlock;
{
   NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc]
        initWithConcurrencyType:NSPrivateQueueConcurrencyType];    
   backgroundContext.parentContext = 
        self.managedDocument.managedObjectContext;
   [backgroundContext performBlock:^{
          NSArray *figuresInBackgroundContext = 
          [self managedObjectsInArray:figures passedToContext:backgroundContext];
// …

调试代码时,第一个代码段中的局部变量tmpFormulanil,但其值应该与缓存的值相同。

为什么我的缓存不起作用的任何想法或想法?

更新

正如我发现的那样 - 感谢您的帮助,我的托管对象因未知方法而出现故障。 -willTurnIntoFault(调试器中的命令bt)的回溯产生:

thread #24: tid = 0x8f50b, 0x000b7eb4 Demo`-[Figure willTurnIntoFault](self=0x17f18610, _cmd=0x3432fe08) + 20 at Figure.m:104, queue = 'NSManagedObjectContext Queue, stop reason = breakpoint 6.1
    frame #0: 0x000b7eb4 Demo`-[Figure willTurnIntoFault](self=0x17f18610, _cmd=0x3432fe08) + 20 at Figure.m:104
    frame #1: 0x2d8fd6ea CoreData`-[NSFaultHandler turnObject:intoFaultWithContext:] + 66
    frame #2: 0x2d9648f8 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _disposeObjects:count:notifyParent:] + 320
    frame #3: 0x2d964c16 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) _dispose:] + 682
    frame #4: 0x2d95f8d2 CoreData`-[NSManagedObjectContext _dealloc__] + 402
    frame #5: 0x2d95fb2e CoreData`internalBlockToDeallocNSManagedObjectContext + 70
    frame #6: 0x38818e7a libdispatch.dylib`_dispatch_queue_drain + 374
    frame #7: 0x38815f92 libdispatch.dylib`_dispatch_queue_invoke + 42
    frame #8: 0x38819744 libdispatch.dylib`_dispatch_root_queue_drain + 76
    frame #9: 0x388199c4 libdispatch.dylib`_dispatch_worker_thread2 + 56
    frame #10: 0x38943dfe libsystem_pthread.dylib`_pthread_wqthread + 298

如何找到'-willTurnIntoFault'的来电者?

1 个答案:

答案 0 :(得分:1)

您的瞬态属性代码看起来很不错。 tmpFormula应该是 一个局部变量,可以稍微简化一下:

- (NSString*)formula 
{
    NSString *tmpFormula;
    [self willAccessValueForKey:@"formula"];
    tmpFormula = [self primitiveValueForKey:@"formula"];
    [self didAccessValueForKey:@"formula"];

    if (tmpFormula == nil) {
        NSString *formulaEnc = self.formulaEnc;
        NSLog(@"Decryption started.");
        // ... decrypt ...
        tmpFormula = decryptedString;
        self.formula = tmpFormula;
    }
    return tmpFormula;
}

这个问题也与解密无关。

问题在于托管对象 只能存在于创建它们的托管对象上下文中。

您似乎在背景MOC上创建对象并将它们放入全局 用于缓存的数组。但是一旦背景MOC被释放,所有对象都会被释放 会自动变为故障,您无法再访问其属性。 (您将获得nil或可能是运行时异常)。 所以这种缓存是行不通的。