On 2009 May 17, at 15:10, Ben Trumbull wrote:

Core Data supports == and != searches against binary data. You should be able to just use a predicate like:

[NSPredicate predicateWithFormat:@"myTransformableAttribute = %@", myGuidObject]

and have it "just work".

Read the above carefully!

myGuidObject is an NSData, right? So when you make that predicate with %@, it becomes a string description, complete with angle brackets and a whitespace separating each group the four bytes. Core Data is actually comparing the ^descriptions^ of NSData objects. Yuck!!

Months ago, I wrote code with using -[NSComparisonPredicate predicateWithLeftExpression:rightExpression:modifier:type:options:]. I used -[NSExpression expressionWithConstantValue:] to create the expressions. The left expression value was the name of an attribute which is of type "Binary Data", and the right expression value was an NSData object. This seemed to be reasonable because -[NSExpression expressionForConstantValue:] takes an id as a parameter.

Result: It worked fine with the XML store (Why??). But when I switch to the SQLite store, it crashes when Core Data sends a -UTF8String message to the data object -- because it's expecting a damned description string. Took me several hours before I finally read Ben's post very carefully and figured out why it was doing that.

Did I miss some documentation somewhere, or is this kind of a bug?

To work around, I now use the following method in place of - expressionForConstantValue, and my app is happy. Does this make sense?

@implementation NSExpression (NSDataSupport)

+ (NSExpression*)betterExpressionForConstantValue:(id)value {
    if (![value respondsToSelector:@selector(UTF8String)]) {
        value = [value description] ;
    }

    return [self expressionForConstantValue:value] ;
}

Thanks,

Jerry Krinock


P.S. If anyone would like a little demo of how NSExpression + NSData works fine with the XML store and fails with the SQLite store, here ya go.....

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface NSData (DebugBadMessage)

- (char*)UTF8String ;

@end

@implementation NSData (DebugBadMessage)

- (char*)UTF8String {
    NSLog(@"\n   Core Data has just sent -UTF8String to NSData %...@\n"
          "   In real life, you'd crash here, but we've implemented\n"
          "   -UTFString so you can get away with it in this demo.",
          self) ;
    return NULL ;
}

@end

// Note: This function returns a retained, not autoreleased, instance.
NSManagedObjectModel *getStaticManagedObjectModel() {
    static NSManagedObjectModel *mom = nil;

    if (mom != nil) {
        return mom;
    }

    mom = [[NSManagedObjectModel alloc] init];

NSEntityDescription *fooEntity = [[NSEntityDescription alloc] init];
    [fooEntity setName:@"Foo"];
    [fooEntity setManagedObjectClassName:@"Foo"];
    [mom setEntities:[NSArray arrayWithObject:fooEntity]];

    NSMutableArray* properties = [[NSMutableArray alloc] init] ;
    NSAttributeDescription *attributeDescription;

    attributeDescription = [[NSAttributeDescription alloc] init];
    [attributeDescription setName:@"data"];
    [attributeDescription setAttributeType:NSBinaryDataAttributeType];
    [attributeDescription setOptional:YES];
    [properties addObject:attributeDescription] ;
    [attributeDescription release] ;

    [fooEntity setProperties:properties];
    [properties release] ;

    [fooEntity release] ;

    return mom;
}

NSManagedObjectContext *CreateManagedObjectContext(NSString* storeType) {
    NSLog(@"\n\n***** Creating moc with type %@ *****", storeType) ;

NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];

    NSPersistentStoreCoordinator *coordinator =
    [[NSPersistentStoreCoordinator alloc]
     initWithManagedObjectModel: getStaticManagedObjectModel()];
    [moc setPersistentStoreCoordinator: coordinator];
    [coordinator release] ;

    NSString* path ;
    path = [NSHomeDirectory() stringByAppendingPathComponent:@"Junk"] ;

    NSError *error;

    NSURL* storeUrl = [NSURL fileURLWithPath:path] ;
    NSPersistentStore *newStore ;
    newStore = [coordinator addPersistentStoreWithType:storeType
                                         configuration:nil
                                                   URL:storeUrl
                                               options:nil
                                                 error:&error];

    if (newStore == nil) {
        NSLog(@"Store Configuration Failure\n%@",
              ([error localizedDescription] != nil) ?
              [error localizedDescription] : @"Unknown Error");
    }
    return moc;
}

void TestFetch(NSString* storeType) {
NSManagedObjectContext *moc = CreateManagedObjectContext(storeType);

    // Create the data we'll use to test our predicate.
    // Any data will do.
    NSData* data = [@"Hello" dataUsingEncoding:NSUTF8StringEncoding] ;

#define ADD_AN_OBJECT 1
    // The following section is optional.  The problem still
    // occurs whether there is an object in the store or not.
#ifdef ADD_AN_OBJECT
    // Insert a Foo
    NSManagedObject* foo ;
    foo = [NSEntityDescription insertNewObjectForEntityForName:@"Foo"
                                        inManagedObjectContext:moc] ;

    // And the following statement is optional too.
    // In other words, it doesn't matter whether the object is
    // in the store matches the predicate or not.
    [foo setValue:data
           forKey:@"data"] ;
#endif

    // Create a fetch request
    NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"Foo"
                                        inManagedObjectContext:moc]];

    NSExpression* lhs = [NSExpression expressionForKeyPath:@"data"] ;
NSExpression* rhs = [NSExpression expressionForConstantValue:data] ;
    NSPredicate* predicate ;
    predicate = [NSComparisonPredicate predicateWithLeftExpression:lhs
                                                   rightExpression:rhs
modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType
                                                           options:0] ;

    NSLog(@"Here's the predicate:\n%@", predicate) ;
    [fetchRequest setPredicate:predicate] ;

    // Execute the fetch request
    NSLog(@"Executing fetch request...") ;
    NSArray* fetches = [moc executeFetchRequest:fetchRequest
                                          error:NULL] ;
    NSLog(@"Fetched returned %d objects", [fetches count]) ;


    [moc release] ;
}

int main (int argc, const char * argv[])
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSManagedObjectModel *mom = getStaticManagedObjectModel();

    TestFetch(NSXMLStoreType) ;

    TestFetch(NSSQLiteStoreType) ;

    [mom release] ;
    [pool release] ;

    return 0;
}
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to