"for x in" syntax with NSArray - objective-c

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];
}

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))];

There's no need to resort to NSArray. As CodaFi says, "If you would like to iterate over C-structs (like CGPoints), use a standard for-loop with a C-array." Well then, why not do so?
static CGPoint items[] = {
{50, 50},
{270, 50},
{50, 360},
{270, 360},
};
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
This creates the array at compile-time, not run-time! Then iterate the array:
for (NSUInteger i = 0; i < ARRAY_SIZE(items); ++i)
[self someMethod:items[i]];
For another example involving an array of dictionaries, see Objective-C Is Still C (Not Java!)

Related

AnyObject To CGPoint

I cant seem to figure this out, I have a Objective-C function that returns an NSArray, I know for sure that data inside the NSArray contains CGPoint objects How in the world do I cast this to an Array
Here is the function
+(NSArray *)translatePoints:(NSArray *)points fromView:(UIView *)fromView toView:(UIView *)toView
{
NSMutableArray *translatedPoints = [NSMutableArray new];
// The points are provided in a dictionary with keys X and Y
for (NSDictionary *point in points) {
// Let's turn them into CGPoints
CGPoint pointValue = CGPointMake([point[#"X"] floatValue], [point[#"Y"] floatValue]);
// Now translate from one view to the other
CGPoint translatedPoint = [fromView convertPoint:pointValue toView:toView];
// Box them up and add to the array
[translatedPoints addObject:[NSValue valueWithCGPoint:translatedPoint]];
}
return [translatedPoints copy];
}
Your translatesPoints method returns an NSArray that contains NSValues that wrap CGPoints. Let's create such an array:
let arr:NSArray = [NSValue(CGPoint: CGPointMake(1,2)), NSValue(CGPoint: CGPointMake(3,4))]
You can get the values from this array and call CGPointValue() on them:
for val in arr as [NSValue] {
let point = val.CGPointValue()
println("CGPoint = (\(point.x), \(point.y))")
}
If you want, you can convert the entire NSArray to a Swift array of CGPoints like this:
let points = (arr as [NSValue]).map({$0.CGPointValue()})
Now points has the type [CGPoint].

How do I get objects that I set in my NSMutableDictionary and make a touch interface?

I am trying to make grid with touch capabilities using a NSMutableDictionary. I created a coordinate grid (_coordinateRecords being my dictionary) using this in the viewDidLoad function of the view controller:
[self _loopOnCellWithIterator: (^(int iLooper, int jLooper)
{
int cellWidth = 10;
int space = 1;
[_coordinateRecords setObject: [NSIndexPath indexPathForRow: iLooper inSection: jLooper] forKey: [NSValue valueWithPointer: redCell]];
redCell = [[[UIView alloc] initWithFrame: CGRectMake(iLooper * (cellWidth + space) + 24.25,
jLooper * (cellWidth + space) + 110,
cellWidth, cellWidth)] init];
_cells[iLooper][jLooper] = redCell;
[redCell setBackgroundColor: [UIColor blueColor]];
[[self view] addSubview: redCell];
})];
using this block:
- (void)_loopOnCellWithIterator: (void(^)(int iLooper, int jLooper))iterator
{
for (int iLooper = 0; iLooper < kCellSize; iLooper++)
{
for (int jLooper = 0; jLooper < kCellSize; jLooper++)
{
iterator(iLooper, jLooper);
}
}
}
So, I was wondering how I can call upon the objects in the dictionary that I set.
I'm not exactly sure what you're asking, but two things may help:
You access the values in a dictionary using keys. The method -objectForKey: takes a key and returns the associated object. You're expected to know what the keys are, but there's also a method that provides an array containing all the keys.
If you're having a hard time mapping from grid coordinates to dictionary keys, perhaps you're using the wrong data structure. An array may be more suitable since its easy to convert from coordinates to indices.

Predicate editor issue

Inside my custom scroll view i have added predicate object as under. It is giving error in the methods predicateWithSubpredicates in debug stack. Here is my sample code please let me know if any error are present.
-(void) awakeFromNib
{
NSPredicateEditor *predicateeditor = [[NSPredicateEditor alloc] initWithFrame:NSMakeRect(0, 0, 200, 150)];
NSArray *leftExpressions = [NSArray arrayWithObjects:[NSExpression expressionForKeyPath:#"date"], nil];
NSAttributeType rightType = NSDateAttributeType;
NSComparisonPredicateModifier modifier = NSAllPredicateModifier; //don't need "ANY" or "ALL"
NSArray *operators = [NSArray arrayWithObjects:[NSString stringWithString:#"Today"],[NSString stringWithString:#"Tomorrow"],[NSString stringWithString:#"Next week"], nil];
NSUInteger options = 0;
NSPredicateEditorRowTemplate *rowTemplate = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions:leftExpressions rightExpressionAttributeType:rightType modifier:modifier operators:operators options:options];
[predicateeditor setRowTemplates:[NSArray arrayWithObject:rowTemplate]];
[rowTemplate release];
[self addSubview:predicateeditor];
[predicateeditor addRow:nil];
[predicateeditor displayValuesForRow:1];
[predicateeditor release];
}
As you've written it, this is going to define a predicate like this:
ALL date {"Today", "Tomorrow", "Next Week"} {a user-entered date}
I hope you can see that this is non-sensical.
For starters, if you really mean that //don't need "ANY" or "ALL", then you shouldn't be be using NSAllPredicateModifier. You should be using NSDirectPredicateModifier.
Also, the things that are allowed to go in the operators array are NSNumber objects that box one of the built-in predicate operator values.
So: what are you trying to accomplish?

How to use NSPointArray?

So I want to use the method appendBezierPathWithPoints:count: in NSBezierPath. But the method requires me to use NSPointArray. The documentary doesn't really talk much about it and all I could get about it is that it's an array of NSPoints and I'm not sure how to do it. I think that it uses the c array mechanism, but I'm not sure.
Thanks.
Yes, you need a C-style array of points to pass to appendBezierPathWithPoints:count:. For example you might do something like this:
NSPoint pointArray[3];
pointArray[0] = NSMakePoint(0, 0);
pointArray[1] = NSMakePoint(0.5, 0.25);
pointArray[2] = NSMakePoint(1, 1);
[lines appendBezierPathWithPoints:pointArray count:3];
where lines is an instance of NSBezierPath.
In a more complicated case you'll use a variable number of points say.
If you want to use Objective-C style array, then you have to use NSValue class for this purpose.
NSMutableArray *array = [NSMutableArray array];
CGPoint myPoint;
myPoint.x = 100;
myPoint.y = 200;
[array addObject:[NSValue valueWithPoint:myPoint]];
To retrieve an NSPoint back from the array:
myPoint = [array[0] pointValue];
Hope it helps.

Using CGPoints in an NSArray

I have been trying to create an array stating the location of a UIImageView in an app I've been working on. What I am trying to do is by using an array I can store the location of my "player" image by using its x,y and z coordinates. The script I am trying to accomplish would look like
NSArray *location[3];
-(IBAction)startup;{
[location addObject: player.center.x];
[location addObject: player.center.y];
[location addObject: playerheight];
}
So I will be able to access this array to move my "player" on the screen in "3-dimensions", but I don't know how to convert the CGpoint values to NSValues so they can be used in the array, is there a simple way to do this inside of the array?
To convert floating point values to objects, use NSNumber. NSValue has wrappers for geometric types like CGPoint. Either would work for you.
[NSValue valueWithCGPoint:player.center];
[NSNumber numberWithFloat:player.center.x];
[NSNumber numberWithFloat:player.center.y];
To addition for the first answer.
When you'll need to read CGPoint back from your array, you can use something like that:
CGPoint point = [(NSValue *)[pointsArray objectAtIndex:i] CGPointValue];
Also note that there's no addObject method for NSArray (you can't add objects to an NSArray after its been created); you want NSMutableArray.
Instead of:
NSArray *location[3];
you probably want something more like:
NSMutableArray *location = [NSMutableArray arrayWithCapacity:3];
Does it have to be an NSArray? Why not use an array of structs?
typedef struct {
CGPoint location;
CGFloat height;
} PlayerLocation;
PlayerLocation players[3];
players[0].location = player.center;
players[0].height = playerheight;
Or depending on your design it may make more sense to declare an objective-C class that contains the x,y,z coordinates as ivars and store those objects into an NSArray.
#interface PlayerLocation : NSObject {
CGPoint location;
CGFloat height;
}
#end