Shortly: how to determine if id is CFType or not at runtime
i’m implementing dynamic core data attributes and in willSave method of ExtendedManagedObject i wanna check if the id value is CFType to store it into plist file.
If I’m trying to save to plist UIImage, that is not toll-free bridged with CF (apple docs), I am getting an error:
2011-11-17 17:16:25.294 [490:707] Error saving extended data: Property list invalid for format (property lists cannot contain objects of type ‘CFType’)
Can I check it with some method or I have to implement by myself (just isKindOfClass from docs)?
I don’t want to implement accessors in NSManagedObject subclass, I dont know exactly how many urls I’ll get from entities properties. Question is about dynamic extended attributes at runtime.
- (void)willSave
{
NSDictionary *changes = [self valueForKey:@"extendedChanges"];
if (changes!=nil) {
// merge changes into snapshot
NSMutableDictionary *dict = [[self extendedSnapshot] mutableCopy];
NSEnumerator *e = [changes keyEnumerator];
NSString *key;
while (key=[e nextObject]) {
id value = [changes objectForKey:key];
if (value==[NSNull null])
[dict removeObjectForKey:key];
else if (#ugly and I'm not shure is thread safe **else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]] || [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]])**)
[dict setObject:value forKey:key];
}
// archive as binary plist
NSData *data = nil;
if ([dict count]>0) {
NSString *error=nil;
data = [NSPropertyListSerialization dataFromPropertyList:dict
format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
if (error!=nil) {
NSLog(@"Error saving extended data: %@", error);
[error release];
}
}
[dict release];
[self setPrimitiveValue:data forKey:@"extendedData"];
}
[super willSave];
}
That’s a wrong way to approach the problem. The blog post you referenced saves the extended attributes as a serialized plist. The plist can contain only the following types of objects, as written in the official doc:
Other classes are just not allowed. Don’t add objects of any other class to the attributes extended this way.
Also, saving an image file in a CoreData database is not a good idea, generally speaking, read On Blobs in the official doc. Instead, save the
UIImagein a file and write the file path in the CoreData database.If you just have a transient property which is not saved to the database, you don’t even have to go through the trouble of creating extended attributes. Just add it as a property of a subclass of
NSManagedObject:without adding
thumbnailin the CoreData model. Then do the corresponding@synthesizein the.mfile. The property added this way to a managed object is just not saved.If you want to keep unknown number of thumbnails, you can put an
NSDictionary(orNSArray) containingUIImage*s.If you really do want to get
CFTypefrom anNSObject*, do the following:The ugly
ifclause is there because there’s no public function which gives you theCFTypeIDof an un-bridged Objective-C object.Read CFType reference. But I don’t recommend doing this.