Skip to content

Instantly share code, notes, and snippets.

@iljaiwas
Created May 19, 2020 09:52
Show Gist options
  • Save iljaiwas/e7faab710a86be50d3a5f8af8461e8de to your computer and use it in GitHub Desktop.
Save iljaiwas/e7faab710a86be50d3a5f8af8461e8de to your computer and use it in GitHub Desktop.
Tinkering with a predicate builder in Objective-C.
/* I'm trying to come up with with a general predicate builder in Objective-C, that can build NSPredicates for
arbitrary classes. I want to write something like this:
predicate = [[[[[builder name] contains:@"ilja"] age] greaterThan:@20] predicate];
But the compiler insists on sprinkling ids everywhere.
predicate = [[(id)[[(id) [(id) builder name] contains:@"ilja"] age] greaterThan:@20] predicate];
Any ideas how to omit the 'id' casts? Also, need a good idea for or and not methods.
Feel free to paste this code into CodeRunner.
*/
#import <Foundation/Foundation.h>
@interface Person: NSObject
@property NSString *name;
@property NSNumber *age; /* I' rather have an int property, but the compiler doesn't like sending messages to int */
@end
@implementation Person
@end
@interface IHPredicateBuilder: NSObject
+ (id) predicateBuilderForClass:(Class) inClass;
- (id) contains:(NSString*) value;
- (id) equals:(id) value;
- (id) lessThan:(NSNumber*) value;
- (id) lessThanOrEqual:(NSNumber*) value;
- (id) greaterThan:(NSNumber*) value;
- (id) greaterThanOrEqual:(NSNumber*) value;
/* No idea how to this so far
- (id) not:(IHPredicateBuilder*) predicate;
- (id) or:(IHPredicateBuilder*) inPredicates;
*/
@property Class targetClass;
@property NSString *lastKey;
@property NSPredicateOperatorType lastOperatorType;
@property NSPredicate *predicate;
@end
@implementation IHPredicateBuilder
+ (id) predicateBuilderForClass:(Class) inClass
{
IHPredicateBuilder *result = [[self alloc] init];
result.targetClass = inClass;
return result;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSString *selectorName = NSStringFromSelector( aSelector);
if ([self.targetClass instancesRespondToSelector:aSelector]) {
NSString *selectorName = NSStringFromSelector( aSelector);
self.lastKey = selectorName;
return [self methodSignatureForSelector:@selector(mirror)];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([self.targetClass instancesRespondToSelector:anInvocation.selector]) {
anInvocation.selector = @selector(mirror);
[anInvocation invokeWithTarget:self];
return;
}
[super forwardInvocation:anInvocation];
}
- (id) mirror
{
return self;
}
- (id) contains:(NSString*) inValue
{
[self addPredicateWithOperatorType: NSContainsPredicateOperatorType value:inValue];
return self;
}
- (id) equals:(id) inValue
{
[self addPredicateWithOperatorType: NSEqualToPredicateOperatorType value:inValue];
return self;
}
- (id) lessThan:(NSNumber*) inValue
{
[self addPredicateWithOperatorType: NSLessThanPredicateOperatorType value:inValue];
return self;
}
- (id) lessThanOrEqual:(NSNumber*) inValue
{
[self addPredicateWithOperatorType: NSLessThanOrEqualToPredicateOperatorType value:inValue];
return self;
}
- (id) greaterThan:(NSNumber*) inValue
{
[self addPredicateWithOperatorType: NSGreaterThanPredicateOperatorType value:inValue];
return self;
}
- (id) greaterThanOrEqual:(NSNumber*) inValue
{
[self addPredicateWithOperatorType: NSGreaterThanOrEqualToPredicateOperatorType value:inValue];
return self;
}
- (void) addPredicateWithOperatorType:(NSPredicateOperatorType) inType value:(id) inValue
{
NSPredicate *newPredicate = [NSComparisonPredicate predicateWithLeftExpression:[NSExpression expressionForKeyPath:self.lastKey]
rightExpression:[NSExpression expressionForConstantValue:inValue]
modifier:NSDirectPredicateModifier
type:inType
options:NSDiacriticInsensitivePredicateOption];
if (self.predicate == nil) {
self.predicate = newPredicate;
} else {
self.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[self.predicate, newPredicate]];;
}
}
/* No idea yet
- (id) or:(NSArray<IHPredicateBuilder*>*) inPredicates
{
}
- (id) not:(IHPredicateBuilder*) predicate
{
}
*/
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
Person *dummy = [[Person alloc] init];
dummy.name = @"ilja";
dummy.age = @100;
IHPredicateBuilder *builder = [IHPredicateBuilder predicateBuilderForClass:Person.class];
NSPredicate *predicate = [[(id)[[(id) [(id) builder name] contains:@"ilja"] age] greaterThan:@20] predicate];
NSLog (@"should evaluate to 1: %d", [predicate evaluateWithObject:dummy]);
dummy.age = @5;
NSLog (@"should evaluate to 0: %d", [predicate evaluateWithObject:dummy]);
}
}
@iljaiwas
Copy link
Author

So that's defined as
#define UI_APPEARANCE_SELECTOR attribute((annotate("ui_appearance_selector")))

Looks like I'd need to hack the compiler to get rid of the warnings?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment