I am getting the message:
*** _NSAutoreleaseNoPool(): Object 0x3f43660 of class UICFFont
autoreleased with no pool in place -
just leaking
I have placed a break point using the symbol _NSAutoreleaseNoPool and the program does break, however, the stack trace does not show me any of my code only some UIView and Core Animation layer code.
alt text http://img.skitch.com/20100614-fw7u4qtb5bprpwrkh9rdkwn3rq.png
Is there a better way to get to the bottom of the issue? There is apparently a thread that does not have an auto release pool, but I can't figure out where.
Thanks.
Are you using CATiledLayer instances ? This is the only type of layer I know that can have their drawLayer:inContext: method called from an arbitrary thread:
As more data is required by the
renderer, the layer's
drawLayer:inContext: method is called
on one or more background threads to
supply the drawing operations to fill
in one tile of data. The clip bounds
and CTM of the drawing context can be
used to determine the bounds and
resolution of the tile being
requested.
Related
Intention: creating CGLayer offscreen, draw some complicated stuff on it from second thread and use it later for quick drawing on main thread
Problem: CGLayerCreateWithContext(context, size, info) expects an already existing CGContext so that it knows for what kind of context it needs to be optimized.
Solution I found so far: CGContextRef ctx = UIGraphicSetCurrentContext()
but this function doesn't seem to exist anymore.
Question: Isn't there another way to access something like a default context? Or do i really need to wait for the first drawRect: call just for accessing UIGraphicsGetCurrentContext() and creating all CGLayers from main thread with one wasted drawing run?
you can create an image context by doing something like:
UIGraphicsBeginImageContext(rect);
// your drawing code
UIGraphicsEndImageContext();
with that said, i'm not sure you can do this from a thread other than main. worth a try, though.
I have a scene called Level1, which takes the hero and the enemy from a layer called GameLayer. I heard that an efficient way of doing this is using tags and retrieving it using getChildByTag. I tried this out, but I'm having many issues. I'm using SneakyInput. On Level1, there is a leftJoystick (for enemy movement), and a rightJoystick (for firing projectiles). I have an addEnemy and addHero method in my GameLayer, which I call. Everything I've mentioned works.
In my Level1 scene I have a method called moveHero (which obviously is supposed to move the hero with the joystick.). Through basic debugging I know the problem is the geteChildByTag line. I test out the hero's position through NSLog, and it's saying 0,0. Which is weird because on screen you can see the hero. But I also realized I'm calling the addHero method without using getChildByTag.
I hope I'm being clear here. I've uploaded GameLayer.h and GameLayer.m onto 4shared. http://www.4shared.com/file/PqhjoMFy/GameLayer.html
Hopefully you can take a look at it and point me in the right direction.
BTW: There are no errors or crashes. It's just not working.
Thanks in advance.
getChildByTag will never crash, it's a pretty nicely coded method that just loops through the children array of the object and checks to see if any objects match, that way you don't get assertion issues.
You have some serious issues here with your code.
Firstly..
GameLayer *heroInstance = [[GameLayer alloc] init];
CCSprite *hero = (CCSprite *)[heroInstance getChildByTag:1];
NSLog(#"Hero position X: %f", hero.position.x);
NSLog(#"Hero position Y: %f", hero.position.y);
This will never work, heroInstance is a brand new object, it has no children, also you've just created a memory leak here.
Your hero is a child of the spritesheet, which is a child of the scene.
To reference your child you must call getChildByTag on your spritesheet (which you probably need to reference by calling getChildByTag on your scene..
something like this.
[[self getChildByTag:spritesheet] getChildByTag:hero];
Also, use an enum, so that you don't have to remember what numbers certain tags are (look at the cocos2d example projects).
I'm creating an application where the user can draw a line on a screen from an object to the location they want to send it and the object will then follow the line to the final location. In order to do this, I've already created working methods to allow the user to draw the lines and then to store the coordinates of the line in a MutableArray. However, I'm having some trouble when I try to animate. As I'm pretty new to the iPhone OS, this could be a simple problem, but I haven't been able to find a solution yet.
I am NOT using Bezier Paths as the user is drawing the line manually, I'm not drawing it programmatically.
Here's the code that I've tried
-(void)animateButtonWasPressed
{
for (int f = 0; f < [cordArrayY count]; f++) {
NSString *newY = [cordArrayY objectAtIndex:f];
NSString *newX = [cordArray objectAtIndex:f];
[self myAnimate:newX :newY];
}
}
-(void)myAnimate:(NSString *)PntX :(NSString *)PntY
{
[UIView animateWithDuration:.5 animations:
^{
object.center = CGPointMake([PntX floatValue], [PntY floatValue]);
}];
}
SYNTAX:
object - the object I am trying to move
cordArray - the mutable array containing the x-coordinates
cordArrayY - the mutable array containing the y-coordinates
Everything else is either defined within the code or Apple methods
The problem: the object moves instantly from its original location directly to the final location. I get a NSLog which tells me this:
-[UIApplication endIgnoringInteractionEvents] called without matching -beginIgnoringInteractionEvents. Ignoring.
Any help would be appreciated!
The method you're using to animate "object" seems to be ok. I believe the problem is the loop in which you are invoking that method. You are trying to animate the same property of the object over and over in every step of that loop. I think this causes that "jump".
Take a look at this quote from Apple's docs:
Important: Changing the value of a property while an animation
involving that property is already in progress does not stop the
current animation. Instead, the current animation continues and
animates to the new value you just assigned to the property.
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6
As a consequence of invoking the animation in each step, you will end up animating object in approximately 0.5 secs to the last position of your coordinates array.
I think you should link those animations together, but you should wait for each animation to finish to start the following one. Take a look at this
Another thing that both the animateWithDuration:animations:completion:
and animateWithDuration:delay:options:animations:completion: methods
support is the ability to specify a completion handler block. You
might use a completion handler to signal your application that a
specific animation has finished. Completion handlers are also the way
to link separate animations together.
Hope this helps,
Cheers.
I was finally able to solve this problem:
At first I tried to continue using the method that I had above. Lio's advice to use the "completion" block was perfect, but as I needed it to loop for an undefined number of times, I would have to use a counter variable. iPhone block programming doesn't allow the modification of external variables or the use of the _block declaration, so this didn't work out for me.
However, I eventually created my entire animation using NSTimer in the method described here just using my array coordinates instead:
http://www.icodeblog.com/2008/10/28/iphone-programming-tutorial-animating-a-ball-using-an-nstimer/
Which, if either, of these methods would be an appropriate place to:
Change the text of a CATextLayer
Load a different image into a CAImageLayer
Tell sublayers to update themselves
Dude I may be way drunk ... but there is NO drawRect method in CAlayers
I think you can use drawInContext: to actually (gulp) draw in to CALayers, but nobody is man enough to do that since WW2.
Regarding display, you don't need to call it, it basically updates what you set using .contents.
I just use .contents something like this ...
[self.view setLayer:rearLayer];
[self.view setWantsLayer:YES];
rearLayer.frame = CGRectMake(gameBlah,gameBlah, 1024,768);
// note that we are dealing there with the mysteries of rearLayer positioning;
// it is measured by the SUPER layer of the layer in question!
// (indeed much as frame for the view is, if you think about it ..)
rearLayer.contents = (id)loadMacStylePng(#"spaceShip");
Say one had the guts to write one's own drawInContext: ...
In that case, it gets called (or abstracted out ... or recalculated, or something) when you call displayAsNeeded. (I've never needed to call displayAsNeeded:, that's for sure.)
This issue really has me stumped...
I have an iPad project that I use UIPanGestureRecognizer and I am using the following method call within my handlePanGesture:
- (AIEnemyUnit *) hitTestForEnemyUnit:(CGPoint)where {
CALayer * layer = [self hitTest:where];
while (layer) {
if ([layer isKindOfClass:[AIEnemyUnit class]]) {
return (AIEnemyUnit *)layer;
} else {
layer = layer.superlayer;
}
}
return nil;
}
Once I "find" an AIEnemyUnit layer, I continue with the drag and everything works fine. Except about around the 6th to 10th "drag" I get a crash with the debugger deep within only the CALayer -hitTest:
modifying layer that is being finalized - 0x124530
*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason:
'*** -[NSCFSet hitTest:]: unrecognized selector sent to instance 0x124530'
From the symptoms it looks like you have an over-release of a CALayer.
Two areas you should check:
1) Are you 'saving' this CALayer in a variable without retaining it? If you're hitting any autorelease pools (including the one supplied on the main thread) then these layers could be getting released unintentionally. As noted in the comments, since these aren't autoreleased, this can happen without hitting a pool. It can happen anytime the CALayer is released while you're holding a reference however.
2) You're explicitly calling release on this layer later on. Since you are given this layer as is (both hitTest: and superlayer return objects without an extra retain count) you do not have ownership, and thus should not release it.
Another useful tool for debugging is using NSZombies, and some other techniquies linked there. NSZombies basically allows your application to crash the moment you access a released object, which hopefully will give you a more meaningful stack trace.
I think there's a bit of 'misinformation' in the hitTest documentation actually. I ran into a similar problem myself putting 4 instances of a subclassed view onto the window, each with four sublayers in it. Each of the 4 view subclasses had a touchesBegan:withEvent method and a touchesEnded:withEvent method defined. I found that if my touch landed or ended in the top-left most view, my hitTest returned a valid sublayer. However, hitTests in any of the other three views returned nil for the sublayer. Like you, I was totally stumped until I decided to replace the touch point in the view's co-ordinate system with one for the window's co-ordinate system and then it all worked. I reproduce the documentation for the hitTest method:
hitTest:
Returns the farthest descendant of the receiver in the layer hierarchy (including itself) that contains a specified point.
- (CALayer *)hitTest:(CGPoint)thePoint
Parameters
thePoint
A point in the coordinate system of the receiver's superlayer.
Return Value
The layer that contains thePoint, or nil if the point lies outside the receiver’s bounds rectangle.
Availability
Available in Mac OS X v10.5 and later.
Declared In
CALayer.h
I would argue, based on my observations, that the explanation of 'thePoint' is wrong. I think it should read 'A point in the coordinate system of the window containing the receiver.' I think the only reason the top-left view gave valid hitTests was because the co-ordinates of the touch - in that location - are the same as the co-ordinates of the touch in the window. Don't know if this helps you but it's helped me get my logic working.
V.V.