Reputation: 425
I need to pass an IF statement to a method. In JavaScript you can assign a function to a variable. Then that variable can be passed to a function and executed. Does this exist in Objective-C?
This is the pattern I'd like to implement:
-(void)singleComparisonWith:(NSArray *)data
IndexBegin:(NSUInteger)indexBegin
IndexEnd:(NSUInteger)indexEnd
Threshold:(float)threshold {
NSIndexSet *set1 = [self searchWithData:data
Range:[self makeInspectionWithRange:indexBegin
End:indexEnd]
Option:NSEnumerationConcurrent
Comparison:XXXXXXXXX];
// XXXXXXXXX is an IF statement that looks for value at an index above threshold
}
-(void)rangeComparisonWith:(NSArray *)data
IndexBegin:(NSUInteger)indexBegin
IndexEnd:(NSUInteger)indexEnd
ThresholdLow:(float)thresholdLow
ThresholdHigh:(float)thresholdHigh {
NSIndexSet *candidates = [self searchWithData:data
Range:[self makeInspectionWithRange:indexBegin
End:indexEnd]
Option:NSEnumerationReverse
Comparison:YYYYYYYYY];
// YYYYYYYYY is an IF statement that looks for value at an index above thresholdLow and above thresholdHigh
}
-(NSIndexSet *)searchWithData:data
Range:(NSIndexSet *)range
Option:(NSEnumerationOptions)option
Comparison:(id)comparison {
return [data indexesOfObjectsAtIndexes:range
options:option
passingTest:^(id obj, NSUInteger idx, BOOL *stop){
// Comparison is used here. Returns YES if conditions(s) are met.
}
];
}
EDIT:
Here's the solution thanks to @Charles Srstka.
NSIndexSet *set1 = [self searchWithData:data
Range:[self makeInspectionWithRange:indexBegin
End:indexEnd]
Option:NSEnumerationConcurrent
Comparison:BOOL^(id o) {
return ([o floatValue] > threshold);
}
];
-(NSIndexSet *)searchWithData:data
Range:(NSIndexSet *)range
Option:(NSEnumerationOptions)option
Comparison:(BOOL(^)(id o))comparison {
return [data indexesOfObjectsAtIndexes:range
options:option
passingTest:^(id obj, NSUInteger idx, BOOL *stop){
return comparison(obj);
}
];
No errors in that segment.
Thank you for your help.
Upvotes: 0
Views: 100
Reputation: 17050
What you want in Objective-C is called block syntax. While certainly not the nicest thing to look at, or the easiest thing to remember, it will do what you want.
// declares a block named 'foo' (yes, the variable name goes inside the parens)
NSUInteger (^foo)(NSString *) = ^(NSString *baz) {
return [baz length];
};
// now you can call foo like a function:
NSUInteger result = foo(@"hello world");
// or pass it to something else:
[someObject doSomethingWith:foo];
// A method that takes a block looks like this:
- (void)doSomethingWith:(NSUInteger (^)(NSString *))block;
This site is a handy "cheat sheet" that lists all the ways to declare a block in Objective-C. You will probably be referring to it often. The URL I linked to is a newer, work-friendly mirror. I'm sure you can guess the site's original URL if you think about it. ;-)
Basically whenever you see a ^
in Objective-C, you're looking at a block declaration. Unless, of course, you're looking at an XOR operation. But usually it's a block.
EDIT: Look at the site I linked to, where it says "as an argument to a method call." You need to declare it using that syntax, i.e.
... comparison: ^BOOL(id o) {
return ([o floatValue] > threshold);
}];
I know it's not the most intuitive syntax in the world, which is why that site is useful as a cheat sheet.
Also, unrelated to your issue, but Objective-C naming convention is to start the argument labels with lower-case letters; i.e. range:
, options:
, and comparison:
rather than Range:
, Option:
, Comparison:
.
Upvotes: 3