OK. This was bugging me so I thought about it some more... I think the easiest way is to have some sort of "session" object and then have a "derived property" on your managed object. Assuming you have an entity called UserData with a property called encryptedData, I whipped up some code that might help illustrate:
@interface UserData : NSManagedObject
@property (nonatomic, retain) NSData * unencryptedData;
@end
@interface UserData () // Private
@property (nonatomic, retain) NSData * encryptedData;
@end
// These functions defined elsewhere
NSData* Encrypt(NSData* clearData, NSData* key);
NSData* Decrypt(NSData* cipherData, NSData* key);
@interface UserSession : NSObject
+ (UserSession*)currentSession;
- (id)initWithUserName: (NSString*)username andEncryptionKey: (NSData*)key;
@property (nonatomic, readonly) NSString* userName;
@property (nonatomic, readonly) NSData* encryptionKey;
@end
@implementation UserData
@dynamic encryptedData;
@dynamic unencryptedData;
+ (NSSet*)keyPathsForValuesAffectingUnencryptedData
{
return [NSSet setWithObject: NSStringFromSelector(@selector(encryptedData))];
}
- (NSData*)unencryptedData
{
UserSession* session = [UserSession currentSession];
if (nil == session)
return nil;
NSData* key = session.encryptionKey;
NSData* encryptedData = self.encryptedData;
NSData* decryptedData = Decrypt(encryptedData, key);
return decryptedData;
}
- (void)setUnencryptedData:(NSData *)unencryptedData
{
UserSession* session = [UserSession currentSession];
NSAssert(session, @"No user session! Can't encrypt!");
NSData* key = session.encryptionKey;
NSData* encryptedData = Encrypt(unencryptedData, key);
self.encryptedData = encryptedData;
}
@end
@implementation UserSession
static UserSession* gCurrentSession = nil;
+ (UserSession*)currentSession
{
@synchronized(self)
{
return gCurrentSession;
}
}
+ (void)setCurrentSession: (UserSession*)userSession
{
@synchronized(self)
{
gCurrentSession = userSession;
}
}
- (id)initWithUserName: (NSString*)username andEncryptionKey: (NSData*)key
{
if (self = [super init])
{
_userName = [username copy];
_encryptionKey = [key copy];
}
return self;
}
-(void)dealloc
{
_userName = nil;
_encryptionKey = nil;
}
@end
The idea here is that when a given user logs in you create a new UserSession object and call +[UserSession setCurrentSession: [[UserSession alloc] initWithUserName: @"foo" andEncryptionKey: <whatever>]]. The derived property (unencryptedData) accessor and mutator get the current session and use the key to transform the values back and forth to the "real" property. (Also, don't skip over the +keyPathsForValuesAffectingUnencryptedData method. This tells the runtime about the relationship between the two properties, and will help things work more seamlessly.)