CALayer Array with Multiple of Same Object - iphone

Am I trying to create a game where an obstacle is constantly fired at the user. I have an NSMutableArray so I can access all the obstacles as a group. Here is my code:
CALayer *obstacle = [[[CALayer alloc] init] autorelease];
UIImage *obstacleImage = [UIImage imageNamed:#"Obstacle.png"];
obstacle.contents = (id)obstacleImage.CGImage;
obstacle.bounds = CGRectMake(0, 0, starImage.size.width/2, starImage.size.width/2);
int xPosition = (arc4random()%(360-0))+0;
obstacle.position = CGPointMake(xPosition, 20);
[self.view.layer addSublayer:obstacle];
[self.obstacleArray addObject:obstacle];
My questions is: How would I access the objects in this array? I want to be able to access the latest object so I can animate it. I have looked through the NSMutableArray Class Reference , but still can't find anything. I have tried this:
NSLog(#"%d",[obstacleArray indexOfObject:obstacle]);
But all it returns is: 0. Is there an easy solution to this problem that I'm just not seeing? Thanks in advance for any responses.

Use [obstacleArray lastObject] or [obstacleArray objectAtIndex:[obstacleArray count]-1] to get the last Object. You can find that in the NSArray Class Reference. (Since it's the parent class of NSMutableArray)

Related

Using NSCopy to Copy a Custom Object Containing Pointers?

I am learning how to use NSCopy. I want to make a copy of a custom object I am using, which is an ImageView in a UIScrollView.
I am trying to implement NSCopying protocol as follows :
-(id)copyWithZone:(NSZone *)zone
{
ImageView *another = [[ImageView allocWithZone:zone]init];
another.imageView = self.imageView;
another.imageToShow = self.imageToShow;
another.currentOrientation = self.currentOrientation;
another.portraitEnlarge = self.portraitEnlarge;
another.landscapeEnlarge = self.landscapeEnlarge;
another.originalFrame = self.originalFrame;
another.isZoomed = self.isZoomed;
another.shouldEnlarge = self.shouldEnlarge;
another.shouldReduce = self.shouldReduce;
another.frame = self.frame;
//another.delegate = another;
another.isZoomed = NO;
[another addSubview:another.imageView];
return another;
}
Then to copy the object in another class :
ImageView * onePre = [pictureArray objectAtIndex:0];
ImageView * one = [onePre copy];
The copy is made however I have one odd problem. The copied object's ImageView (a UIImageView) and ImageToShow (a UIImage) properties seem to be the same as the original objects. This kind of makes sense as in the copy code I am re-pointing a pointer, rather than making a new version of ImageView and ImageToShow.
My question is how do I make a copy of an object that contains pointers to other objects ?
Thanks !
UIView does not conform to NSCopying, but it does conform to NSCoding:
another.imageView = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject:self.imageView]];
This serializes and then deserializes the object, which is the standard way to perform a deep copy in ObjC.
EDIT: See https://stackoverflow.com/a/13664732/97337 for an example of a common -clone category method that uses this.

NSMutableArray withObject(UIImageView *)

I am trying to load an NSMutableArray with UIImageViews. Everything is going fine with that.
Unfortunately, I have no idea how to use the objects when they are in the mutable array.
Here is some code:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
NSMutableArray *array = [NSMutableArray new];
[array loadWithObject:(UIImageView *)imageView];
[imageView release];
That kind of sets up what I've done. Here's what I want to do:
[array objectAtIndex:5].center = GCRectMake(0, 0);
but that doesn't work. How can I do this??
OK, I'll explain the problems you're having. The way to do what you are trying to do is the following:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
NSArray *array = [NSArray arrayWithObject:imageView];
[imageView release];
[[array objectAtIndex:0] setCenter:CGPointMake(0.0,0.0)];
First, there is no method -[NSMutableArray loadWithObject:]. Likewise, for your example, you don't really even need a mutable array. Mutable objects have their place, but I usually try to use immutable ones when it makes sense to; as such, I've used NSArray.
Next, you never need to typecast objects when you're adding them to an array. There are a few reasons wherefore your example didn't work:
You were accessing the sixth (starting at one) object in the array. Was there an instance of UIImageView at that index?
For some reason, dot-notation for getters and setters only works when the compiler knows the type of the object you're sending a message to. Since the type of an object that is coming out of an array is not clear at compile-time, you can't use dot-notation. Instead, just use old-fashioned Objective-C method-sending syntax ("brackets and colons").
Finally, it's Core Graphics, not Gore Craphics: hence the prefix is CG, not GC. Also, -[UIImageView setCenter:] takes a CGPoint, not CGRect. So the function you wanted was CGPointMake.
Best of luck to you! Let me know if this helps clear some things up.
I think you should refer NSMutableArray.
However, I am just giving an overview of NSMutableArray.
NSMutableArray = Next Step (NS) Mutable Array
Mutable means array can be modified as and when required.
Now, This mutable array can hold any kind of objects.
Assume that I want to store strings in an array. I would write following statements.
NSMutableArray *anArray=[[NSMutableArray alloc] init];
[anArray addObject:#"Sagar"];
[anArray addObject:#"pureman"];
[anArray addObject:#"Samir"];
Here, I found that you need to store imageViews in your requirements.
NSMutableArray *anArray=[[NSMutableArray alloc] init];
UIImageView *imgV1=[[UIImageView alloc] initWithFrame:CGRectMake(10,50,60,70)];
UIImageView *imgV2=[[UIImageView alloc] initWithFrame:CGRectMake(10,110,60,70)];
UIImageView *imgV3=[[UIImageView alloc] initWithFrame:CGRectMake(10,170,60,70)];
UIImageView *imgV4=[[UIImageView alloc] initWithFrame:CGRectMake(10,210,60,70)];
[anArray addObject:imgV1];
[anArray addObject:imgV2];
[anArray addObject:imgV3];
[anArray addObject:imgV4];
Now, once ImageViews are added to array, release imageviews as array has it's retain count.
[imgV1 release];
[imgV2 release];
[imgV3 release];
[imgV4 release];
Above code will add images to NSMutableArray
When you use one of the image from an array, just write down this thing
UIImageView *x=[anArray objectAtIndex:0];
Hope Above descriptions work for you.
Add comment, if you don't understood.

How can I modify a CGRect stored as NSValue in an NSArray?

I am creating an NSArray with CGRects using the following line:
[self setMyArray:[NSArray arrayWithObjects:[NSValue valueWithCGRect:CGRectMake(x,y,z,a)], [NSValue valueWithCGRect:CGRectMake(x,y,z,a)], nil]]
I am then trying to update the CGrects in the Array every so often like this:
for (NSValue *bound in myArray)
{
CGRect myRect = [bound CGRectValue];
myRect.origin.y += 2;
}
However this is not working, when the loop runs again, the origin is still the same. I am assuming this has something to do with the NSValue wrapper?, What can I do so the value is actually updated in the array?. Thank you.
-Oscar
NSValue objects are immutable so there is nothing you can do. You should use a mutable array and replace the existing object with a new NSValue instance containing the new rect.
As others mentioned, NSValue instances are not mutable so you will have to recreate them and then replace them in an NSMutableArray.
Another option is to use more 'classic' C memory management (malloc/free) and manage your array that way. There is nothing wrong with going that route. You just have to be more careful as it is not has high level as the Objective-C/Foundation APIs.
// Create an array to hold 100 rectangles
CGRect* rectangles = (CGRect*) malloc(100 * sizeof(CGRect));
// Change the rectangle at index 2 (remember arrays are 0 based, so this is the 3rd)
CGRect* rect = &rectangles[2];
rect->size.width /= 2.0;
// Shortcut for accessing rectangles
rectangles[2].size.width = 100.0;
// Get rid of the array
free(rectangles);
Might be faster too if you work on for example a game.

Using a variable in a statement to reference the image stored in a UIImageView

UPDATED Scroll down to see the question re-asked more clearly....
If I had the name of a particular UIImageView (IBOutlet) stored in a variable, how can I use it to change the image that is displayed. I tried this, but it does not work.
I'm still new to iphone programming, so any help would be appreciated.
NSString *TmpImage = #"0.png";
NSString *Tst = #"si1_1_2";
TmpImage = #"1.png";
UIImage *sampleimage = [[UIImage imageNamed:TmpImage] retain];
((UIImageView *) (Tst)).image = sampleimage; // This is the line in question
[sampleimage release];
RESTATED:
I have a bunch of images on the screen.... UIImageView *s1, *s2 ,*s3 etc up to *s10
Now suppose I want to update the image each displays to the same image.
Rather than doing
s1.image = sampleimage;
s2.image = sampleimage;
:
s10.image = sampleimage;
How could i write a for loop to go from 1 to 10 and then use
the loop var as part of the line that updates the image.
Something like this.
for ( i = 1; i <- 10; ++i )
s(i).image = sample; // I know that does not work
Basic question is how do I incorporate the variable as part of the statement to access the image? Don't get hung up on my example. The main question is how to use a variable as part of the access to some element/object.
Bottom Line... If I can build the name of a UIImageView into a NSString object, How can I then use that NSString object to manipulate the UIImageView.
Thanks!
Ugh! Your line in question:
((UIImageView *) (Tst)).image = sampleimage;
is casting a string pointer as a UIImageView pointer - you're basically saying that your pointer to a string is actually a pointer to a UIImageView! It will compile (because the compiler will accept your assertion happily) but will of course crash on running.
You need to declare a variable of type UIImageView. This can then hold whichever view you want to set the image of. So your code could look like the following:
NSString *TmpImage = #"0.png";
UIImageView *myImageView;
If (someCondition == YES) {
myImageView = si1_1_2; //Assuming this is the name of your UIImageView
} else {
myImageView = si1_1_3; //etc
}
UIImage *sampleimage = [UIImage imageNamed:TmpImage]; //no need to retain it
myImageView.image = sampleImage;
Hopefully this makes sense!
Edit: I should add, why are you trying to have multiple UIImageViews? Because a UIImageView's image can be changed at any time (and in fact can hold many), would it not be better to have merely one UIImageView and just change the image in it?

Adding UIImageView to an NSMutableDictionary

I'm trying to add multiple instances of UIImageView(s) to an NSMutableArray of NSMutableDictionar(ies).
I am doing this, to be able to go back and pull out the UIImageView reference, to change the position of these images.
It seems that, when I pull the info out of the Dictionary, that it only returns a null pointer...
Any suggestions on how I should implement this? There may be a way easier method to store a list of n images and be able to reference them later....
// (for i = 0 to 30)
UIImageView *newBall = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"ball.png"]];
newBall.center = CGPointMake (arc4random() % 280 + 20, arc4random() % 440 + 20);
[self.view addSubview:newBall];
NSMutableDictionary *dictBall = [[[NSMutableDictionary alloc] init] autorelease];
[dictBall setValue:newBall forKey:#"imgBall"];
// the dictionary is then added to the array
[newBall release];
// end for loop
(I'm using a Dictionary, because I also store a dy/dx value for rate of change in movement)
Code above doesn't look OK to me.
You're creating a new NSMutableDictionary *dictBall everytime through the loop. Is something retaining it after the loop exists? Doesn't look like it from your code. This may be why your object is nil.
Move this line outside/before the for loop, and you should be fine.
Also, are you sure you want to store UIViewImage in a dictionary? Why not just an ID (based on the tag) and the coordinates (CGPoint or CGRect)? This way you can use the tag to find the UIimageView via the tag and move it where ever you want? Less expensive memory wise.