How to build an array from an array of arrays - objective-c

I am fairly new to iOS development.
I have a viewController that contains a property that is an object of a custom class. We'll call that custom class ClassA. The object of ClassA has a property that is an NSMutableArray of objects of another custom class we'll call ClassB. ClassB has a property that is also an NSMutableArray of objects of type CLLocation.
From inside a method in the viewController I need to create a C array of CLLocationCoordinate2D structs (CLLocationCoordinate2D is a property of CLLocation). Each of these CLLocationCoordinate2D's needs to come from all of the CLLocation objects held by all of the objects in ClassB and ClassA. If I'm understanding what I've wrought, I believe I have a 3-D array.
I'm stuck on exactly how to go about assembling this array of structs. If it were just one array I would do something like this:
NSUInteger numberOfSteps = [objectOfClassX count];
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [objectOfClassX objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
However I'm struggling with the syntax of getting each object in the first array, then inside that each object in the second array, then inside that the CLLocationCoordinate2D.

Iterate once to get the total count of coordinates, then iterate again to copy them into a newly-allocated array.
NSInteger coordCount = 0, coordIndex = 0;
for(ClassA *a in collectionOfA)
for(ClassB *b in a.collectionOfB)
coordCount += [b.locations count];
CLLocationCoordinate2D coords[coordCount];
for(ClassA *a in collectionOfA)
for(ClassB *b in a.collectionOfB)
for(CLLocation *location in b.locations)
coords[coordIndex++] = location.coordinate;

just have a try : coordinates = [NSMutableArray arrayWithArray: objectOfClassX];

Related

how do I set the values of an array in Objective-C using .notation?

Sorry I'm new to Objective-C and I'm still figuring out how to set properties using dot notation. I have 3 files as follows... towards the end(in main), I've set the radius property and the logged it, but I'm not sure how to set the center property because it's not a float (like radius) it's an array. I originally tried something like—
ball.center = {12, 14, 16} does not work.
My class .m file is:
#implementation Sphere
-(void)setCenter:(NSArray *)center radius:(float)radius {
_center = center;
_radius = radius;
}
#end
my class .h file is:
#interface Sphere : NSObject
#property (nonatomic) float radius;
#property (nonatomic, strong) NSArray *center;
-(void)setCenter:(NSArray *)center radius:(float)radius;
#end
and my main file is:
int main(int argc, const char * argv[])
{
#autoreleasepool {
Sphere *ball = [[Sphere alloc] init];
ball.radius = 34;
**// ball.center = an array, so how do we set that?**//
**//do I have to set the values of the array first?//**
NSLog(#"\nball radius %f\n", ball.radius);
**//I want to be able to log the values of the array the way I logged the radius.**
}
return 0;
}
I'll reply to your question "how I can create an array with numbers", but it looks like you don't need an array at all (read all the answer :-))
The first thing that you need is to initialize your array, for example:
NSArray *array = [NSArray arrayWithObjects:object1, object2, object3, nil];
There is also the literal that allows you to do the same thing with a friendly synthax
NSArray *array = #[object1, object2, object3];
Note that you can only insert objects in an NSArray and not primitives, so you need some NSNumber (a NSNumber is an object that represents a number).
You can use a class method to create a NSNumber
NSNumber *one = [NSNumber numberWithInt:1];
Or the literal synthax (usually preferred for its brevity)
NSNumber *one = #(1);
So, something like this will do
NSArray *array = #[#(1), #(2), #(3)];
However, I see that you want to represent the center, usually to do it, you don't use an array of objects, you use a CGPoint, that is not an array, it is a struct that contains 1 point (i.e. X and Y), and it is perfect to represent the center!
So the code will look like:
#implementation Sphere
-(void)setCenter:(CGPoint)center radius:(float)radius {
_center = center;
_radius = radius;
}
#end
and to use it:
Sphere *ball = [[Sphere alloc] init];
ball.center = CGPointMake(10, 20);
NSLog(#"my ball center x:%d y:%d", ball.center.x, ball.center.y);

Most efficient way of changing the value of a CGPoint in a CGPoint array?

I have constructed a CG Point array as follows:
NSMutableArray *_startPositions = [NSMutableArray array];
[_startPositions addObject:[NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)]];
[_startPositions addObject:[NSValue valueWithCGPoint:CGPointMake(0.0, 0.0)]];
How can i most efficiently change the x and y values of the points in the array?
If I retrieve the value using:
CGPoint myPoint0 = [[_startPositions objectAtIndex:0] CGPointValue];
I get back a copy of the point. How can I change the x and y values of the CGPoints in the array? I could remove the CGPoint at any position and replace it with one with the correct x,y values, but is there a more efficient way?
Use C array instead of NSMutableArray. If required use C++ STL collection classes such as std::vector or other C/C++ collection library. In this way, you can manipulate the array content without any Obj-C method call.
I suggest you create your own class as
.h
#interface MyPoint : NSObject {
CGPoint point;
}
#property (nonatomic,assign) CGPoint point;
#end
.m
#implementation MyPoint
#synthesize point;
#end
Then add your MyPoint Object in your array.
Change it like
MyPoint *myPoint = [_startPositions objectAtIndex:0];
myPoint.point = myPoint0;
From the docs:
NSValue objects are always immutable.
So your only option here is to create a new NSValue to replace the old one when the CGPoint value changes. If you are looking for a more efficient way to store an array of CGPoints, then a C array is the easiest and fastest way to go.
If you are changing just the 'x' or 'y' value of CGPoint point, you can do this:
((CGPoint *)&point)->x += dx;
or
((CGPoint *)&point)->y += dy;

Add a tag to NSMutableArray

Is it possible to set a tag for an NSMutableArray? I have to somehow determine, in an array of arrays, the single array which needs to be rewritten, and if I could just set the tag to that inner array to 1 (or some other number), this would be extremely easy.
Example:
NSMutableArray* outerArray = [NSMutableArray new];
NSMutableArray* innerArray1 = [NSMutableArray new];
NSMutableArray* innerArray2 = [NSMutableArray new];
NSMutableArray* innerArray3 = [NSMutableArray new];
NSMutableArray* innerArray4 = [NSMutableArray new];
[outerArray addObject:innerArray1];
[outerArray addObject:innerArray2];
[outerArray addObject:innerArray3];
[outerArray addObject:innerArray4];
//now let's say innerArray1 needs to be rewritten
//I would like to be able to do this
[innerArray1 setTag:100];
//then later, when I need to determine which of the arrays inside outerArray
//needs to be rewritten, I can just do this
for(NSMutableArray* temp in outerArray) {
if(temp.tag == 100) {
//do what I need to do
}
}
But you can't use setTag: with NSMutableArrays. What would be a workaround?
Arrays are ordered collections, so why don't you just keep track of which index needs to be rewritten.
When something happens such that the array at index 0 (which, in your example, would be innerArray1) of outer array needs to be written, cache index 0 -- as a property if this routine needs to span across separate methods.
Then, when it comes time to do the rewrite, consult the cached index. Retrieve the array to be rewritten like this: NSArray *arrayToRewrite = [outerArray objectAtIndex:cachedIndexToRewrite]; Or access it directly: [[outerArray objectAtIndex:cachedIndexToRewrite] replaceObjectAtIndex:whatever withObject:whatever];
You could use an NSMutableDictionary instead. The "tag" would just be the key and the array would be the value.
Use associated objects. You can even add a category to NSMutableArray that would add a tag property to them.
#interface NSMutableArray (TagExtension)
#property (nonatomic, assign) NSInteger tag;
#end
#implementation NSMutableArray (TagExtension)
#dynamic tag;
static char TagExtensionKey;
-(NSInteger)tag {
NSNumber *ourTag = (NSNumber *)objc_getAssociatedObject(self, &TagExtensionKey);
if( ourTag ) {
return( [ourTag integerValue] );
}
return(0);
}
-(void)setTag:(NSInteger)newTag {
objc_setAssociatedObject(self, &TagExtensionKey, [NSNumber numberWithInteger:newTag], OBJC_ASSOCIATION_RETAIN);
}
#end
See also: How to add properties to NSMutableArray via category extension?
Not sure why a dictionary is a bad idea here… as alternatives, you can:
remember the index
or if each entry is a unique array, you can simply refer to it by pointer:
NSArray * tagged = theArray;
for (NSMutableArray * at in outerArray) {
if (tagged == at) {
//do what I need to do
}
}
Make your inner arrays class variables. Then you can just access them as:
for(NSMutableArray* temp in outerArray) {
if(temp == self.innerArray1) {
//do what I need to do
}

How to declare class array in objective c

I can declare NSMutableArray or NSArray but I want to declare class array. Let say user is a class so I can declare array as:
user* obj[10];
it is valid in Objective c, but I am not sure how I can set array capacity dynamically. Which we usually do with MutableArray as initWithCapacity:..
This is what I am doing with class:
user* objuser;
CustomOutput* output = [[CustomOutput alloc] init];
[objuser cutomSerialize:output];
NSMutableData* data = output.data;
But If I have array as:
NSMutableArray* aryUserObj;
I can't call cutomSerialize method from arryUserObj.
I want to Serialize all the userObj at ones and get a single NSData object.
The standard approach to serialize an array of objects is for you to define encodeWithCoder: and initWithCoder: in your User object:
#interface User: NSObject {
....
}
-(void)encodeWithCoder:(NSCoder*)coder ;
-(id)initWithCoder:(NSCoder*)coder;
#end
What you currently have in CustomSerialize should be in these methods.
Then, if you want to encode an object, you do
User* user=... ;
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:user];
and decode it:
User* user=[NSKeyedUnarchiver unarchiveObjectWithData:data];
If you have an array of objects,
NSMutableArray* array=... ; // an array of users
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:array];
and
NSArray* array=[NSKeyedUnarchiver unarchiveObjectWithData:data];
Iteration over array is done automatically.
Note also that you don't get the mutable array back, it's an immutable array.
NSMutableArray * users = [NSMutableArray array];
for (int i = 0; i < someNumber; ++i) {
User * aUser = [[User alloc] initWithStuff:someStuff];
[users addObject:aUser];
[aUser release];
}

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