I am working on a game in Cocos2d for iPhone.
In my init method I have an object (type id) declared as follows (also note bossDir is declared as 1):
bossMov = [CCMoveTo actionWithDuration:1.0f position:ccp(75*bossDir, 320-55)];
[boss runAction:bossMov];
Then in a timer method I have:
if ([bossMov isDone] == YES) {
bossDir = -bossDir;
[boss stopAllActions];
[boss runAction:bossMov];
}
It moves the boss once, but after that it gives EXC_BAD_ACCESS and points me to a line in the file "CCTimer.m" that says:
if( elapsed >= interval ) {
impMethod(target, selector, elapsed); //This line in particular.
elapsed = 0;
}
How can I fix this problem?
have you tried the NSZombieEnabled because i am not a cocos2d guy but just as a suggestion i am telling you this. Because bad access error comes only when you are pointing to an object which is no longer in the memory and the application crashes if you try to do so
You are not retaining bossMov action. So when you call [boss stopAllActions]; it is released and deallocated. Then you are trying to run the deallocated action - so you get the bad access.
Related
So I'm working on a simple calculator program to get used to cocoa and objective C. I've redone the whole thing multiple times and every time I finish coding, the first time i build it, it works fine, but every time after that the window wont launch and it gives me these errors:
2013-01-11 10:32:14.760 Visual Caluclator Fix[39892:403] *** Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1138.47/AppKit.subproj/NSCell.m:1564
2013-01-11 10:32:14.762 Visual Caluclator Fix[39892:403] Ignoring exception raised in __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3: Invalid parameter not satisfying: aString != nil
I've concluded that the problem lies in my textEdited method, because when I comment the code inside of it out, the program has no issues running; however, I have no idea why this is, or why it would run the first time and not any subsequent times. When I put in an exception breakpoint, it points me to the one line in the updateUI method and the call to [self updateUI] in the textEdited method. The following code is the textEdited method and the other methods it references.(I'm fairly sure there's nothing wrong with the solve method because I used it in a command prompt calculator and it worked great. Also, I know this is a pretty convoluted way to program a calculator, with the strings and everything, but I was just trying to integrate the code I already had for the command prompt program into a cocoa program.)
In the AppDelegate class:
- (void)updateUI{
[self.calculationView setStringValue: self.calculation.calcString];//Exception breakpoint points here
}
- (IBAction)textEdited:(id)sender {
self.calculation.calcString = self.calculationView.stringValue;
[self.calculation solve];
[self updateUI];//Exception breakpoint points here
}
In the Calculation class:
- (NSString*)solve{
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"*"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"/"])
[self calcTerm: i];
}
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"+"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"-"])
[self calcTerm: i];
}
return self.calcString;
}
This might help with your problem:
http://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
The site explains how assertion errors work and demonstrate how you would fix an error like that.
It sounds to me like something in calcTerm: is setting calcString to nil. Thus, when you retrieve it later to set the field's string value to it, you end up setting the field's string value to nil, which it doesn't like.
You can check this by logging the value of calcString just before the end of solve. Then, start stringing up log statements and/or breakpoints in calcTerm: to find out how you're swapping out your string for nil.
I use simpleFTP to request document information. I detect memory-leak with instrument as below:
And in the call tree I find out where is the memory leak happened:
The method "_parseListData" as below:
- (void)_parseListData
{
NSMutableArray * newEntries;
NSUInteger offset;
// We accumulate the new entries into an array to avoid a) adding items to the
// table one-by-one, and b) repeatedly shuffling the listData buffer around.
newEntries = [NSMutableArray array];
assert(newEntries != nil);
offset = 0;
do {
CFIndex bytesConsumed;
CFDictionaryRef thisEntry;
thisEntry = NULL;
assert(offset <= self.listData.length);
bytesConsumed = CFFTPCreateParsedResourceListing(NULL, &((const uint8_t *) self.listData.bytes) [offset], self.listData.length - offset, &thisEntry);
if (bytesConsumed > 0) {
........
}
I don't know how to fix this problem.
The method "CFFTPCreateParsedResourceListing" is a system method and it create __NSDate (look at the second pic).
This is where the memory-leak happen.
The CFFTPCreateParsedResourceListing function returns a CFDictionary into the thisEntry variable, which presumably contains the NSDate objects.
The code should call CFRelease on thisEntry once it is finished with it:
// once we're done with thisEntry
if (thisEntry) {
CFRelease(thisEntry);
}
Old post, but useful solution. You can find the answer here BlackRaccoon ftp client.
According to the creator the CFFTPCreateParsedResourceListing method retains twice the NSDate, to override the issue add the next code, be aware of the comments here:
FAQ section
"Actually, in WhiteRaccoon, if you list a directory you will leak NSDate's. The function CFFTPCreateParsedResourceListing in Apple's SDK has a leak in it. I've attempted to "patch" this, however it isn't guaranteed to work. For OS 5.1 it does work."
........
if (parsedBytes > 0)
{
if (listingEntity != NULL)
{
//----- July 10, 2012: CFFTPCreateParsedResourceListing had a bug that had the date over retained
//----- in order to fix this, we release it once. However, just as a precaution, we check to see what
//----- the retain count might be (this isn't guaranteed to work).
id date = [(__bridge NSDictionary *) listingEntity objectForKey: (id) kCFFTPResourceModDate];
if (CFGetRetainCount((__bridge CFTypeRef) date) >= 2)
CFRelease((__bridge CFTypeRef) date);
this works for me
I am new to IPhone programming and am I having trouble solving the following memory leak.
while(numDeckCounter < numDecks){
int cardCounter=1;
for (int i =1; i<=52; i++) {
tempCard = [Card new]; //leaks tool says that this is leaking object
if(i>=1 && i<=13)
{
tempCard.suit = CLUBS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard]; //reference count 2
cardCounter++;
}
else if(i>=14 && i<=26)
{
tempCard.suit = DIAMONDS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else if(i>=27 && i<=39)
{
tempCard.suit = HEARTS;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
else
{
tempCard.suit = SPADES;
tempCard.faceValue = cardCounter;
[deckArr addObject:tempCard];
cardCounter++;
}
if(cardCounter ==14){
cardCounter=1;
}
[tempCard release]; //this causes an EXC_BAD_ACCESS -reference count should be 1
}
numDeckCounter++;
}
I was under the impression that adding an object to the array would increase its reference count by one, then it would be safe to release the object you just added because it would not be deallocated until the array was released bumping which would then release each object in the array. This is when the object should finally be deallocated.
When I add the [tempCard release]; it crashes my app because it can't access the memory location because it has already been deallocated.
From everything I have read, I think what I said above is true. Someone please correct me if I am wrong. Thanks.
I don't see any leaks in the code you presented. (There are some opportunities to slim it down, though, say by moving the identical operations out of the conditionals).
The Leaks tool output is pretty tricky to read. Is it possible that the Card object is leaking one of it's ivars?
Instead of leaks, run static analysis on your product (Product->Analyze). I think it will flag a different part of your code.
Perhaps try [[Card alloc] init] instead of [Card new]. This is just a guess. However trying the IMO more common method of object creation could be helpful.
Check this out: Use of alloc init instead of new
You could also try removing all the code for adding the Cards to the array. So you'd essentially have:
card = [Card new];
[card release];
This could help you find memory issues associated w/ the array retaining the object perhaps?
Of the three parts I want to move, only the last one actually moves. I can't seem to "recycle" the ease action I created.
How is this done the correct way?
- init
{
// initial setup
[self moveParts];
}
- (void)moveParts
{
id action = [CCMoveBy actionWithDuration:1 position:ccp(0,160)];
id ease = [CCEaseInOut actionWithAction:action];
[part1 runAction:ease];
[part2 runAction:ease];
[part3 runAction:ease];
}
Seems like it is a problem with allocating and copying the actions objects. This thread answers my question pretty well, with this post being the summary:
From my experience you can't really retain actions and get any benefit out of them.
There really isn't good way to reuse actions. If you find that you are deallocing too much that the game is unstable then you should forget actions and just schedule a method that does all the work.
Examples (All variables ending with an underscore are class variables "variablename_"):
BAD WAY TO RUN ACTIONS:
.... maybe in init
moveAction_ = [[MoveBy actionWithDuration:1.f position:ccp(100.f, 0.f)]retain];
.... Some other function
[sprite1_ runAction:moveAction_];
[sprite2_ runAction:moveAction_];
That example won't work because both sprite1_, sprite2_ let's say have the same position.
They will definitely not move together! That is because the action is referenced by an actionManager and you just changed the target of that action.
Correct way:
.... maybe in init
moveAction_ = [[MoveBy actionWithDuration:1.f position:ccp(100.f, 0.f)]retain];
.... Some other function
[sprite1_ runAction:[[moveAction_ copy] autorelease]];
[sprite2_ runAction:[[moveAction_ copy] autorelease]];
Now the action will have the correct behavior but you've essentially lost all efficiency of doing a retain in the first place. You've pretty much created two new instantiations of the action.
The code above is exactly the same as:
[sprite1_ runAction:[MoveBy actionWithDuration:1.f position:ccp(100.f, 0.f)]];
[sprite2_ runAction:[MoveBy actionWithDuration:1.f position:ccp(100.f, 0.f)]];
So in the end you've gained no benefit of retaining the action. So why retain?
If you are really worried about the dealloc slowing down the game then the other way is to lose out on the convenience of actions and create your own scheduled action
...somewhere in init
[self schedule:#selector(moveStuff:)];
// do all you actions manually here
- (void) moveStuff:(ccTick) dt
{
CGPoint delta = ccp(100.f,0.f);
sprite1.position = ccp( (sprite1.position.x + delta.x * dt ),
(sprite1.position.y + delta.y * dt ) );
}
So really it's up to you to decide between speed or convenience.
I have the following instance method (adapted from Listing 3-6 of the Event Handling section in the iPhone Application Programming Guide):
- (CGPoint)originOfTouch:(UITouch *)touch
{
CGPoint *touchOriginPoint = (CGPoint *)CFDictionaryGetValue(touchOriginPoints, touch);
if (touchOriginPoint == NULL)
{
touchOriginPoint = (CGPoint *)malloc(sizeof(CGPoint)); // leaks
CFDictionarySetValue(touchOriginPoints, touch, touchOriginPoint);
*touchOriginPoint = [touch locationInView:touch.view];
}
return *touchOriginPoint;
}
Every once in a while my app leaks 16 Bytes as a result of the call to malloc(). I'm not sure how to return touchOriginPoint while free()ing it as well.
If you do not care a minor performance loss, use an NSMutableDictionary and store the point as an NSValue:
NSValue* touchOriginPointValue = [touchOriginPoints objectForKey:touch];
if (touchOriginPointValue == nil) {
touchOriginPointValue = [NSValue valueWithCGPoint:[touch locationInView:touch.view]];
[touchOriginPoints setObject:touchOriginPointValue forKey:touch];
}
return [touchOriginPointValue CGPointValue];
If you must use the CFDictionary approach, you have to find a place to free those malloc-ed memory when the values are not needed. Therefore, you have to pass the values callbacks when creating the dictionary
static void free_malloced_memory (CFAllocatorRef allocator, const void *value) {
free((void*)value);
}
static const CFDictionaryValueCallBacks values_callbacks = {0, NULL, free_malloced_memory, NULL, NULL};
...
touchOriginPoints = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, & values_callbacks);
...
If you must return the malloc'd value from the function, then you have passed the responsibility for freeing the memory to the calling function, or one of its callers.
Since we can't see the calling functions, we can't diagnose any more.
If you are going to be returning an object that is allocated, then either you need to have the caller free() it, or else you need to be using some kind of garbage collection (so it gets freed automatically).
you don't actually return a pointer, the value is copied to a temp value when it is returned, so you aren't really returning the allocation at all, the problem is that you just aren't freeing it either, you add the allocation to the dictionary and just leave it there?
is there like an EndOfTouch function? where you remove the touch from the dictionary? if there is, call free on your allocation there and you should be fine