objective-c image moving problem - iphone

hey i am running into a problem.
i maade an image object that gets added every 2 seconds by an nstimer.
and an update timer updates it so the image goes forward.
but it only goes forward until a new one gets added and i can't solve why.
this is the method for adding it.
-(void)addTarget {
UIImage *image1=[UIImage imageNamed:#"enemy.png"];
image=[[UIImageView alloc]initWithImage:image1];
image.frame=CGRectMake(0,0,50,50);
[self.view addSubview:image];
image.center = CGPointMake(150, 150);
image.tag = 1;
[_targets addObject:image];
[image release];
}
self explaining.
-(void) update {
image.center = CGPointMake(image.center.x+2, image.center.y);
}
and this spawns them.
-(void) spawn {
[self addTarget];
}

Its because you are constantly reallocating the image. You need to be creating a new image1 variable every time and then adding it to an NSMutableArray.
Then in the update method use a for loop to move each image in the array's centre to whatever point.
- (void)update {
for (UIImage *image in _targets) {
image.center = CGPointMake(image.center.x+2, image.center.y);
}
}

Related

Cocos2d NSMutable Array mutated while enumerated

I've been working on a game, and at a point I didn't have issues removing the enemy game objects (right now they are subclassed from CCSprite and I know that's not the best way)
But I'm not sure what I changed to make it crash when the program attempts to removeChild from _targets after they have been added to targetsToDelete.
I tried moving things around, I just don't know how I am adding or editing the array while its being created... Any help or advice would be great!
And actually if you had any pointers on how best to create game enemies, do you subclass NSObject or CCNode? I heard to divide them into component classes but I had no clue what they meant.
//Projectile Target collision
-(void)update:(ccTime)dt {
for (spygot *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
//Collision Detection Player
CGRect playerRect2 = CGRectMake(
_controlledSprite.position.x - (_controlledSprite.contentSize.width/2),
_controlledSprite.position.y - (_controlledSprite.contentSize.height/2),
_controlledSprite.contentSize.width,
_controlledSprite.contentSize.height);
NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
for (Projectile *projectile in _projectiles)
{
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
CGRect projectileRect = CGRectMake(
projectile.position.x - (projectile.contentSize.width/2),
projectile.position.y - (projectile.contentSize.height/2),
projectile.contentSize.width,
projectile.contentSize.height);
BOOL monsterHit = FALSE;
if (CGRectIntersectsRect(projectileRect, targetRect))
{
NSLog(#"hit");
target.mhp = target.mhp - 1;
monsterHit = TRUE;
if (target.mhp <= 0)
{
[targetsToDelete addObject:target];
}
}
for (spygot *target in targetsToDelete)
{
[self removeChild:target cleanup:YES];
[_targets removeObject:target];
}
if (monsterHit)
{
[projectilesToDelete addObject:projectile];
}
[targetsToDelete release];
}
for (Projectile *projectile in projectilesToDelete)
{
[_projectiles removeObject:projectile];
[self removeChild:projectile cleanup:YES];
}
[projectilesToDelete release];
}
It looks like the code that you've pasted is all from within a for loop iterating over _targets. How does the variable target get initialized?
Usually when I get this sort of error it's because I have the code in a block or am in some other way on a nebulous thread. How sure are you that this bit of code is not running more than once at the same time?
You could try wrapping it in the following:
dispatch_async(dispatch_get_main_queue(), ^{
// do everything here.
});
As for advice about using CCSprite for your game enemy objects, my advice is fix it when it becomes a problem. Are you seeing issues with it right now? Premature optimization is almost as bad as doing it wrong in the first place. You'll know better at the end of the project how you should have done it earlier. ;)
I guess you know that you cannot remove elements from the array while you iterate over it. That is why you have targetsToDelete array.
But it looks to me that you do remove targets to soon.
Try this:
finish iterating the main loop and finish collecting targets to the targetsToDelete array and only after main loop is done remove the targets.

uiimageview.image memory leak

In my applicayion i am using a uiimageview ,and it will load diffrent images on a button click. But there is memory leak when i load images, is that needed to release uiimageview.image property before i load another image to it. Any help please...........
code for loading images to uiimageview
-(void)setOverlayImage:(UIImage *)img
{
overlayView.image=nil;
overlayView.image=img;
}
Before i do overlayView.image=img; i hope the memory allocated for the previous image will be replaced with the new image.
Or is that needed to do [overlayView.image release] and then overlayView.image=img;???????
But when i tried to release, the app crashed.
-(void)setOverlayImage:(UIImage *)img
{
overlayView.image=img;
}
This should be sufficient but you can also go for this.
-(void)setOverlayImage:(UIImage *)img
{
if(overlayView)
{
[overlayView release];
overlayView = nil;
}
overlayView = [[UIImageView alloc] initWithImage:img];
overlayView.frame = yourFrame;
// Add this to your parent view
[self.view addSubview:overlayView];
}
Hope this helps

Fetching image From Animating UIImageView

I'm using animation method of for implementing slide show in UIimageView as:
mainSlideShowImageView.animationImages=images;
mainSlideShowImageView.animationDuration = 75.00;
mainSlideShowImageView.animationRepeatCount = 0; //infinite
[mainSlideShowImageView startAnimating];
Now, what I want is to know which image is currently on image view screen.
How can I do so?
If it is not possible please tell that too.
Edit: 'images' here is array of UIImage.
AFAIK, there is no method which returns imageview's current image , however I have created a workaround for this....
array= [NSArray arrayWithObjects:[UIImage imageNamed:#"1.jpg"],[UIImage imageNamed:#"2.jpg"],[UIImage imageNamed:#"3.jpg"],[UIImage imageNamed:#"4.jpg"],[UIImage imageNamed:#"5.jpg"],nil];
mainSlideShowImageView.animationImages= array;
mainSlideShowImageView.animationDuration=15.0;
i=0;
timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:#selector(increase) userInfo:nil repeats:YES];
[mainSlideShowImageView startAnimating];
-(void)increase
{
i++;
if (i>4) {
i=0;
}
}
-(void)getimage
{
UIImage* im = [array objectAtIndex:i];
// im is the current image of imageview
}
I have taken 5 images here and animation duration of 15 , that means image will change at every 3 seconds, so I have kept timer to fire at every 3 seconds ... and since array contains 5 images ... so if 'i' goes beyond 4 I have put it back to 0 in method increase

Objective C: EXC_BAD_ACCESS when generating a UIImage

I have a view that generates an image based on a series of layers. I have images for the background, for the thumbnail, and finally for an overlay. Together, it makes one cohesive display.
It seems to work a dream, except for when it doesn't. For seemingly no reason, I get an EXC_BAD_ACCESS on the specified line below after it's generated somewhere between 8 and 20 images. I've run it through the memory leak tool and allocation tool, and it's not eating up tons of memory and it's not leaking. I'm totally stumped.
Here's the relevant code:
- (UIImage *)addLayer:(UIImage *)layer toImage:(UIImage *)background atPoint:(CGPoint)point {
CGSize size = CGSizeMake(240, 240);
UIGraphicsBeginImageContext(size);
[background drawAtPoint:CGPointMake(0, 0)]; // <--- error here
[layer drawAtPoint:point];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
// Build the layered image -- thingPage onto thingBackground,
// then the screenshot on that, then the thingTop on top of it all.
// thingBackground, thingPage and thingTop are all preloaded UIImages.
-(UIImage *)getImageForThing:(Thing *)t {
[self loadImageCacheIfNecessary];
if (!t.screenshot) {
return [UIImage imageNamed:#"NoPreview.png"];
} else {
UIImage *screenshot = t.screenshot;
UIImage *currentImage = [self addLayer:thingPage toImage:thingBackground atPoint:CGPointMake(0, 0)];
currentImage = [self addLayer:screenshot toImage:currentImage atPoint:CGPointMake(39, 59)];
currentImage = [self addLayer:thingTop toImage:currentImage atPoint:CGPointMake(0, 1)];
return currentImage;
}
}
I can't find anywhere that this is going wrong, and I've been tearing my hair out for a couple of hours on this. It's the final known bug in the system, so you can imagine how antsy I am to fix it! :-)
Thanks in advance for any help.
As to me, I always use -(void)drawInRect: instead of -(void)drawAtPoint:
CGRect rtDraw;
rtDraw.origin = CGPointZero;
rtDraw.size = size;
[background drawInRect:rtDraw];
[layer drawInRect:rtDraw];
And ....
The paint method with UIGraphicsBeginImageContext(size) and UIGraphicsEndImageContext() is not thread-safe.
Those functions will push or pop a context with stack struct, which is managed by system.
EXC_BAD_ACCESS is almost always due to accessing an object that has already been released. In your code this seems to be t.screenshot. Check creation (and retaining if it is an instance variable) of the object returned by Thing's screenshot property.
As it turns out, the error wasn't in the code I posted, it was in my caching of the thingBackground, thingPage and thingTop images. I wasn't retaining them. Here's the missing code, fixed:
-(void)loadImageCacheIfNecessary {
if (!folderBackground) {
thingBackground = [[UIImage imageNamed:#"ThingBack.png"] retain];
}
if (!folderPage) {
thingPage = [[UIImage imageNamed:#"ThingPage.png"] retain];
}
if (!folderTop) {
thingTop = [[UIImage imageNamed:#"ThingTop.png"] retain];
}
}
I will admit I'm still not comfortable with the whole retain/release/autorelease stuff in Objective C. Hopefully it'll sink in one day soon. :-)

can not get setNeedsDisplay to work within a loop for UIImageView

A frequently answered question, I'm afraid but I am pretty much in the dark on this.
Within my view controller I have the following method to switch back and forward between two images a total of 5 times
- (IBAction)cycle{
BOOL select1;
select1=YES;
UIImage *image1 = [UIImage imageNamed:#"image1.png"];
UIImage *image2 = [UIImage imageNamed:#"image2.png"];
for (int i=0; i<5; i++) {
if (select1){
[imageview setImage:image1];
} else {
[imageview setImage:image2];
}
[NSThread sleepForTimeInterval:1.0];
[imageview setNeedsDisplay];
}
}
The problem is that the setNeedsDisplay message does not work within the loop and the view is only updated when the method quits.
Is there any thing I can do here? Is the approach feasible or am I completely down the wrong track. This is very much a test program (I am new to this language) but it would be useful to control something like this programmatically. The next step app will implement randomly changing times between picture changes.
Can anyone help me on this?
Wrong track. Calling
[NSThread sleepForTimeInterval:1.0];
Is only trying to put the main thread asleep. The problem is that this is the thread that's actually does the drawing. You need to end what you're doing and give control bakc to the NS runtime so that it can update gui elements.
Try using NSTimer to create a scheduled timer. Have it repeat with the time interval that you want. All that you then have to do is set the image:
if (select1){
[imageview setImage:image1];
} else {
[imageview setImage:image2];
}
there's no need for
[imageview setNeedsDisplay];
As the imageview will handle that for itself.