Question

How would you implement the following instance method for NSSet:

- (BOOL)containsMemberOfClass:(Class)aClass

Here's why I want to know:

Core Data model: enter image description here

How do I add a Facebook authorization to a user's authorizations NSSet, but only if one doesn't already exist. In other words, a user can have many authorizations (in case I choose to add a Twitter (e.g.) authorization in the future) but should only have one of each kind of authorization. So, if (![myUser.authorizations containsMemberOfClass:[Facebook class]]), then add a Facebook authorization instance to myUser.

Was it helpful?

Solution

Unfortunately, you have to loop through all of the authorizations and check:

@interface NSSet (ContainsAdditions)

- (BOOL)containsKindOfClass:(Class)class;
- (BOOL)containsMemberOfClass:(Class)class;

@end

@implementation NSSet (ContainsAdditions)

- (BOOL)containsKindOfClass:(Class)class {
    for (id element in self) {
        if ([element isKindOfClass:class])
            return YES;
    }
    return NO;
}

- (BOOL)containsMemberOfClass:(Class)class {
    for (id element in self) {
        if ([element isMemberOfClass:class])
            return YES;
    }
    return NO;
}

@end

OTHER TIPS

With Core Data it is actually best practice to use an NSFetchRequest with an NSPredicate. To do that you would have to add an attribute to your Authorization object, something like authorizationType. You could then do the following:

NSManagedObjectContext *moc = [self managedObjectContext];

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY user.authorizations.authorizationType == %@", @"facebook"];
[request setEntity:[NSEntityDescription entityForName:@"Authorization" inManagedObjectContext:moc]];
[request setPredicate:predicate];

NSError *error = nil;
NSArray *result = [moc executeFetchRequest:request error:&error];

You can then check the count of result to see if it exists or not. Using NSPredicate allows you to use any optimizations Apple has added around CoreData. Here are the Apple Docs.

What if you add this instance method to the User class?

- (BOOL)hasFacebookAuthorization {
    NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"user.id == %@", [self id]];
    [fetchRequest setEntity:[NSEntityDescription entityForName:@"Facebook"
                                   inManagedObjectContext:managedObjectContext]];
    [fetchRequest setPredicate:predicate];

    NSError *error;
    NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    if (!result) {
        // TODO: Handle the error appropriately.
        NSLog(@"hasFacebookAuthorization error %@, %@", error, [error userInfo]);
    }

    return [result count] > 0;
}

Your going about this the wrong way. If the types of authorization are something common and important then you should model that in your data model directly instead of trying to impose that structure in external controller code.

If you have a fixed set of authorizations then you should create an entity to model those authorizations.

Facebook{
    accessToken:string
    experationDate:date
    authorization<-->Authorizations.facebook
}

Google{
    username:string
    password:string
    authorization<-->Authorizations.google
}

Authorizations{
    user<-->User.authorizations
    facebook<-->Facebook.authorization
    google<-->Google.authorization
}

Now you have all your authorizations captured in the data model where they belong. To tighten things up more. You could add a custom method to the User class to control adding and removing authorizations.

The key idea here is that all the logic that manages data should be encapsulated in the data model to the greatest extent possible. This allows you to (1) test all data operations independent of the interface and (2) easily add and remove interface elements without breaking the data model.

Old question, but slightly different answer:

NSPredicate *objectTypeFilter = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
    return [evaluatedObject isKindOfClass:NSClassFromString(@"MyObject")];
}];
NSSet *myObjects =[allObjects filteredSetUsingPredicate:objectTypeFilter];
if (myObjects.count>0) {
    // There was at least one object of class MyObject in the allObjects set
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top