Third times the charm? Let me see if I can address your only-transform-when-going-to-disk requirement. Think of this as a hybrid of the other two approaches.
@interface UserSession : NSObject
+ (UserSession*)currentSession;
+ (void)setCurrentSession: (UserSession*)session;
- (id)initWithUserName: (NSString*)username andEncryptionKey: (NSData*)key;
@property (nonatomic, readonly) NSString* userName;
@property (nonatomic, readonly) NSData* encryptionKey;
@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
@interface EncryptingValueTransformer : NSValueTransformer
@end
@implementation EncryptingValueTransformer
- (id)transformedValue:(id)value
{
UserSession* session = [UserSession currentSession];
NSAssert(session, @"No user session! Can't decrypt!");
NSData* key = session.encryptionKey;
NSData* decryptedData = Decrypt(value, key);
return decryptedData;
}
- (id)reverseTransformedValue:(id)value
{
UserSession* session = [UserSession currentSession];
NSAssert(session, @"No user session! Can't encrypt!");
NSData* key = session.encryptionKey;
NSData* encryptedData = Encrypt(value, key);
return encryptedData;
}
@end
The only tricky part here is that you have to be sure that the current UserSession
is set up before you create the managed object context and isn't changed until after the context is saved and deallocated.
Hope this helps.