DataZombies
DataZombies

Reputation: 425

Objective-C: Passing an IF statement as a argument

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

Answers (1)

Charles Srstka
Charles Srstka

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

Related Questions