I've seen a few examples around using NSArray indexOfObjectPassingTest, but I could not make them work (they would not return a valid index). So now I'm trying using an inline block. I have done it by typedef'ing a block, then setting it as a property, synthesizing it, and initializing it in the constructor. However that sort of renders the whole point mute, as I could easily create a method and use it instead (less typing, less effort).
What I'm trying to achieve is something along this:
Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex: ^NSInteger (NSString *keyword){
for (Observations *obs in self.myAppointment.OBSERVATIONS) {
if ([obs.TIME isEqualToString:keyword] == YES) return (NSInteger)[self.myAppointment.OBSERVATIONS indexOfObject:obs];
}
return (NSInteger)-1;
}];
However Xcode simply won't have it. I've tried different variations, but declaring it inline seems to be a problem, which is weird, because as I've said, typedefing it, declaring, and synthesizing it works like this:
Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:findObs(keyword)];
Where findObs is again a defined block that does the same thing. Is this a syntax issue, or am I missing something else more important ?
-objectAtIndex:
takes an NSUInteger
as a parameter, but you're passing it a block (denoted by the ^
). Your second example calls findObs
(which may be your block) with the keyword
argument, passing the result of that call to -objectAtIndex:
.
You probably want to combine -objectAtIndex:
with -indexOfObjectPassingTest:
:
NSString *keyword = /* whatever */;
NSArray *array = self.myAppointment.OBSERVATIONS;
NSUInteger idx = [array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop){
Observations *obs = (Observations*)obj;
return [obs.TIME isEqualToString:keyword];
}];
if (idx != NSNotFound)
Observations *obs = [array objectAtIndex:idx];
This is an example that returns the index of a string in an array of strings. It may be adapted to any kind of object.
NSString* myString = @"stringToFind";
NSUInteger objectIndex = [myStringArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return (*stop = ([obj isEqualToString:myString]));
}];
To answer the original question precisely:
NSString *keyword = @"myKeyword";
NSUInteger index = [self.myAppointment.OBSERVATIONS indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return (*stop = [(Observations*)obs.TIME isEqualToString:keyword]);
}];
Observations *obs = (index!=NSNotFound) ? self.myAppointment.OBSERVATIONS[index] : NULL;
But it's quite strange to compare something called TIME with a keyword… ;)
It's not necessary to typedef or synthesize anything to make your second example work--just return the block from a method, which would look like this:
-(NSUInteger(^)(NSArray *, NSString *))findObs {
return ^(NSArray *array, NSString *keyword) {
for (NSUInteger i = 0; i < [array count]; i++) {
Observations *obs = [array objectAtIndex:i];
if ([obs.TIME isEqualToString:keyword]) {
return i;
}
}
return NSNotFound;
};
}
Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:[self findObs](keyword)];
Here are some good reasons for defining blocks as method return values, rather than inline.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With