I am trying to create a custom NSMutableSet
that doesn't use the standard isEqual:
and hash
selectors on objects.
Typically I want to use this with Parse. I have a NSMutableSet
containing PFObject
subclass instances, and I consider them equal if they have the same objectId
.
I know I could override isEqual:
and hash
in my PFObject
subclass, but I don't want that functionality on all my objects. Besides, Parse uses these methods internally, so I don't want to mess up with them.
Here is what I have come up so far :
#import <Foundation/Foundation.h>
@interface NSMutableSet (Additions)
+ (NSMutableSet *)setWithParseObjectIdIsEqualCallback;
@end
#import "NSMutableSet+Additions.h"
@implementation NSMutableSet (Additions)
static Boolean ParseObjectIdIsEqualCallback(const void *value1, const void *value2)
{
PFObject *obj1 = (__bridge id)value1;
PFObject *obj2 = (__bridge id)value2;
NSCParameterAssert([obj1 isKindOfClass:PFObject.class]);
NSCParameterAssert([obj2 isKindOfClass:PFObject.class]);
NSCParameterAssert([obj1 isMemberOfClass:obj2.class]);
return [obj1.objectId isEqualToString:obj2.objectId];
}
static CFHashCode ParseObjectIdHashCallback(const void *value)
{
PFObject *object = (__bridge id)value;
NSCParameterAssert([object isKindOfClass:PFObject.class]);
return object.objectId.hash;
}
+ (NSMutableSet *)setWithParseObjectIdIsEqualCallback
{
CFSetCallBacks callbacks = kCFTypeSetCallBacks;
callbacks.equal = ParseObjectIdIsEqualCallback;
callbacks.hash = ParseObjectIdHashCallback;
CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorDefault, 0, &callbacks);
return CFBridgingRelease(set);
}
@end
I don't really know if it will work or if it is safe to use, and I'm quite unfamiliar with Core Foundation objects and functions like CFBridgingRelease()
.
I think your approach is needlessly complicated: you could provide your own isEqual:
and hash
implementations in a wrapper class, and wrap your PFObject
s in it before placing in the NSMutableSet
:
@interface PFObjectWrap {
PFObject *_obj;
}
-(BOOL)isEqual:(id)other;
-(NSUInteger)hash;
+(PFObject*)wrapped;
-(id)initWithPFObject:(PFObject*)obj;
+(PFObjectWrap)wrap:(PFObject*)obj;
@end
@implementation PFObjectWrap
-(id)initWithPFObject:(PFObject*)obj {
if (self = [super init]) {
_obj = obj;
}
return self;
}
+(PFObjectWrap)wrap:(PFObject*)obj {
return [[PFObjectWrap alloc] initWithPFObject:obj];
}
+(PFObject*)wrapped {
return _obj;
}
-(BOOL)isEqual:(id)other {
// Put your custom implementation here
}
-(NSUInteger)hash {
// Put your custom implementation here
}
@end
Now you can wrap your objects into PFObjectWrap
before adding to NSMutableSet
:
NSMutableSet *set = [NSMutableSet set];
[set addObject:[PFObjectWrap wrap:myObject1]];
[set addObject:[PFObjectWrap wrap:myObject2]];
Of course you also need to wrap before searching NSMutableSet
.