Search code examples
objective-crefactoringnsarray

"for x in" syntax with NSArray


I've this kind of instruction:

[self someMethod:CGPointMake(50, 50)];
[self someMethod:CGPointMake(270, 50)];
[self someMethod:CGPointMake(50, 360)];
[self someMethod:CGPointMake(270, 360)];
...

I want to refactor code using NSArray like this:

NSArray items = [NSArray initWithObjects:
                  CGPointMake(50, 50),
                  CGPointMake(270, 50),
                  CGPointMake(50, 360),
                  CGPointMake(270, 360),
                  ...
                  nil];

I dont know right syntax, can someone help me? I'd tried with this, but XCode tells me "Selector element type CGPoint is not a valid object":

CGPoint point = [CGPoint alloc];

for (point in items) {
    [self someMethod:point];
}

Solution

  • for-in loops are an Objective-C concept for iterating over collection classes (that conform to NSEnumeration). If you would like to iterate over C-structs (like CGPoints), use a standard for-loop with a C-array, or wrap the CGPoints in NSValues.

    Here's what your refactoring would look like in modern Objective-C syntax:

    NSArray *items = @[
                      [NSValue valueWithPoint:CGPointMake(50, 50)], //wrap the points in an
                      [NSValue valueWithPoint:CGPointMake(270, 50)], //NSValue so they become
                      [NSValue valueWithPoint:CGPointMake(50, 360)], //first class citizens
                      [NSValue valueWithPoint:CGPointMake(270, 360)],//(Y no boxing?*)
                     ]; //End of collection literal
    for (NSValue *value in items) { //iterate through the NSValues with our points
        [self someMethod:[value pointValue]]; //'un-wrap' the points by calling -pointValue
    }
    

    *My personal struct boxing macro:

    #define STRUCT_BOX(x) [NSValue valueWithBytes:&x objCType:@encode(typeof(x))];