0

I have a problem with NSMutableArray alloc and release. See below code:

NSMutableArray *enemiesToDeleteArray = [NSMutableArray arrayWithCapacity:5];
...
else if ([enemy isActive] && !CGRectIntersectsRect(fieldOfView, enemyRect))
        {
            [enemiesToDeleteArray addObject:enemy];
        }
...
 [enemiesToDeleteArray removeAllObjects];
 [enemiesToDeleteArray release];

Above code crashes in a run. With a symbolic debug break error 'objc_release' or 'malloc_break_error'. Below I added backtrace from the occurence of objc_release error:

* thread #1: tid = 0x1c03, 0x01e140a5 libobjc.A.dylib`objc_release + 21, stop reason = EXC_BAD_ACCESS (code=1, address=0xa0020010)
    frame #0: 0x01e140a5 libobjc.A.dylib`objc_release + 21
    frame #1: 0x01e14bd9 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 555
    frame #2: 0x023c6468 CoreFoundation`_CFAutoreleasePoolPop + 24
    frame #3: 0x002effc1 QuartzCore`CA::AutoreleasePool::~AutoreleasePool() + 19
    frame #4: 0x002ff35f QuartzCore`CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) + 251
    frame #5: 0x002ff75f QuartzCore`CA::Display::TimerDisplayLink::callback(__CFRunLoopTimer*, void*) + 161
    frame #6: 0x023e3376 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
    frame #7: 0x023e2e06 CoreFoundation`__CFRunLoopDoTimer + 534
    frame #8: 0x023caa82 CoreFoundation`__CFRunLoopRun + 1810
    frame #9: 0x023c9f44 CoreFoundation`CFRunLoopRunSpecific + 276
    frame #10: 0x023c9e1b CoreFoundation`CFRunLoopRunInMode + 123
    frame #11: 0x0312b7e3 GraphicsServices`GSEventRunModal + 88
    frame #12: 0x0312b668 GraphicsServices`GSEventRun + 104
    frame #13: 0x009d0ffc UIKit`UIApplicationMain + 1211
    frame #14: 0x000c81f6 MyAPP`main(argc=1, argv=0xbffff36c) + 134 at main.m:14
    frame #15: 0x00001fa5 MyAPP`start + 53

and a backtrace from malloc_break_error:

MyAPP(18609,0xac98ea28) malloc: *** error for object 0x112dee40: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

(lldb) bt
    * thread #1: tid = 0x1c03, 0x97be7815 libsystem_c.dylib`malloc_error_break, stop reason = breakpoint 1.1
        frame #0: 0x97be7815 libsystem_c.dylib`malloc_error_break
        frame #1: 0x97be8d51 libsystem_c.dylib`free + 346
        frame #2: 0x023c5ea4 CoreFoundation`-[__NSArrayM dealloc] + 276
        frame #3: 0x01e159ff libobjc.A.dylib`-[NSObject release] + 47
        frame #4: 0x01e140d5 libobjc.A.dylib`objc_release + 69
        frame #5: 0x01e14bd9 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 555
        frame #6: 0x023c6468 CoreFoundation`_CFAutoreleasePoolPop + 24
        frame #7: 0x002effc1 QuartzCore`CA::AutoreleasePool::~AutoreleasePool() + 19
        frame #8: 0x002ff35f QuartzCore`CA::Display::DisplayLink::dispatch(unsigned long long, unsigned long long) + 251
        frame #9: 0x002ff75f QuartzCore`CA::Display::TimerDisplayLink::callback(__CFRunLoopTimer*, void*) + 161
        frame #10: 0x023e3376 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
        frame #11: 0x023e2e06 CoreFoundation`__CFRunLoopDoTimer + 534
        frame #12: 0x023caa82 CoreFoundation`__CFRunLoopRun + 1810
        frame #13: 0x023c9f44 CoreFoundation`CFRunLoopRunSpecific + 276
        frame #14: 0x023c9e1b CoreFoundation`CFRunLoopRunInMode + 123
        frame #15: 0x0312b7e3 GraphicsServices`GSEventRunModal + 88
        frame #16: 0x0312b668 GraphicsServices`GSEventRun + 104
        frame #17: 0x009d0ffc UIKit`UIApplicationMain + 1211
        frame #18: 0x000c81f6 MyAPP`main(argc=1, argv=0xbffff36c) + 134 at main.m:14
        frame #19: 0x00001fa5 MyAPP`start + 53

Please explain me someone, what am I doing wrong?

1
  • As others have pointed out, simply remove the call to release. You can also delete the call to removeAllObjects -- NSMutableArray instances take care of that automatically during deallocation. Commented Mar 16, 2013 at 15:31

2 Answers 2

4

You should not release enemiesToDeleteArray at all. It will get autoreleased at the end of the current scope. You didn't use alloc at all, so this object is auto managed.

Sign up to request clarification or add additional context in comments.

3 Comments

But why? I mean, there is no attribute given autorelease in allocation of the array.
Did you new, alloc, retain, or copy the NSMutableArray? No? Then don't release it!
Always remember, release comes after NARC.
2

NSMutableArray *enemiesToDeleteArray = [NSMutableArray arrayWithCapacity:5]; returns an autoreleased instance, and that gets cleaned up some time after leaving the initializer. Now the pointer enemiesToDeleteArray points to undefined memory. You need to do:

enemiesToDeleteArray = [[NSMutableArray arrayWithCapacity:5] retain];

or

enemiesToDeleteArray = [[NSMutableArray alloc] initWithCapacity:5];

8 Comments

Not some time later. CS is a science, we don't have magical sometime later.
We do with autoreleasing, actually. From the scope of this method, the time at which release will be called by the system is unknown.
Agreed. From the point of view of this method, it can only assume "sometime later than my return." That is exactly how to think about it.
@JonathanGrynspan It marked as eligible to be garbage collected at the end of the current scope. If you purge your pool, it will happen in quite controlled fashion.
@bioffe The autorelease pool is effectively a mutable counted set of objects at the top of a stack of sets. When you create a pool, a new set is pushed on the stack. When you destroy a pool, the top set is removed, and everything in it (placed there by sending -autorelease) is sent -release once per count.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.