iOS App crashes on exit - objective-c

I'm having an issue where my iOS App is crashing on exit and I've narrowed it down to this:
// File.h
struct Name {
NSString *name;
}
// File.mm
Name names[] = {
#"foo",
#"bar",
};
When the App exits (pushing the home button on the iPad), I get a crash in objc_msgSend with a EXC_BAD_ACCESS (SIGSEGV). It's happening the the destructor Name::~Name().
0 libobjc.A.dylib 0x37586e3a objc_release + 10
1 MyApp 0x0014abfc Name::~Name() (NameManager.h:21)
2 MyApp 0x0014ab42 Name::~Name() (NameManager.h:21)
3 MyApp 0x0014ad94 __cxx_global_array_dtor + 120
4 libsystem_c.dylib 0x36bba1cc __cxa_finalize + 216
5 libsystem_c.dylib 0x36b854f6 exit + 6
Keep in mind that this is in a .mm file, so it's being compiled as obj-c++.
This has worked fine for months and months. I don't know exactly when it started happening, but I suspect it was when I updated to xcode 4.4.
NSString literals should be protected (or always have been) against multiple releases, but I don't think that is happening here anyway.
Does anyone know if something changed in xcode 4.4?
I can fix the crash by doing:
struct Name {
__unsafe_unretained NSString *name;
}
But I hate to do that without understanding why what has worked before no longer works. Or maybe it never should have worked. I also fear a memory over-write, so this might just be a symptom.
This happens in both DEBUG and RELEASE.
UPDATE: I put a breakpoint in ~Name() and verified that memory is not corrupt. LLDB is able to dump the NSString OK. But it crashes when I step.

When you declare a "Plain Old Data" struct in Objective-C++ that contains Objective-C objects with ARC turned on, the compiler is obligated to provide a destructor that correctly deallocates the ObjC members of the struct, even if you do not write them yourself.
This restriction does not apply in Objective-C++. However, nontrivally
ownership-qualified types are considered non-POD: in C++11 terms, they
are not trivially default constructible, copy constructible, move
constructible, copy assignable, move assignable, or destructible. It
is a violation of C++’s One Definition Rule to use a class outside of
ARC that, under ARC, would have a nontrivially ownership-qualified
member.
When you declared that Name structure, the compiler would have written you a destructor involving an implicit strongly held Objective-C object. At execution time, what this means is that the C++ destructor erases what it expects is a C++ structure and instead winds up borking the pointers to the string. With no valid pointer around, the -release ARC tries to send segfaults when it tries to dereference a nonexistent receiver.
When you declare an Objective-C member __unsafe_unretained, it tells ARC to exclude it from the destructor it would have to write, thus the struct is just destroyed, and the -release is never sent. It is recommended that you mark all Objective-C objects in structures or classes as __unsafe_unretained and provide the appropriate memory management yourself, because ARC can significantly complicate object lifetimes across languages.

Related

how to properly alloc/dealloc this pointer? objective-c

*beginner iOS programmer, please explain with patience
suppose i have 2 classes - Foo, Bar
in class Bar, i have a pointer to an instance of Foo, which i set during init. (and because i dont know how to properly import Foo and Bar with each other, i end up setting the type to id instead of Foo)
#implementation Bar{
id pointerToInstanceOfFoo;
}
how do i write my dealloc function for Bar? or DO I even override the dealloc function?
right now i have
-(void)dealloc{
pointerToInstanceOfFoo = NULL;
[super dealloc];
}
i still want that pointer to Foo to be around when Bar dies, but am i doing things right? several questions:
if Foo and Bar imports from each other, how do i do this? or is this bad software design?
right now i have the pointer "pointerToInstanceOfFoo" set in the #implementation... is this equivalent to declaring a private pointer in class Bar?
should i instead be using
#property (nonatomic, weak) id pointerToInstanceOfFoo
instead? if so, why do i keep getting this error about no weak pointers in ARC?
do i need
delete pointerToInstanceOfFoo;
in the dealloc function??
Sorry for the confusion, any explanations/answers would be greatly appreciated!!
P.S. i'm using XCode 4.4 and running on iOS 5.0 with cocos2d v2.1 beta... i think it's using arc
You are not allowed to use [super dealloc] in ARC. So if that compiles, you are not using ARC and you need cals to retain and release. Writing a whole tutorial on that is not something that will fit in a stack overflow answer. As for your other questions:
1) Just import them in the implementation file, not the header file.
2) Yes
3) If it makes you happy. The error probably means you are targeting below iOS 5.0 (I.e. the deployment target in your project settings is set to less than 5.0), in which weak pointers are not supported, or ARC is turned off. I don't think you've accurately reported the error message since it makes no sense.
4) "delete" is not valid objective-c or valid c.
P.S. No, you don't want that pointer to be around after Bar is deallocated because that would be a memory leak. Perhaps you want a static variable instead of an instance variable?
As borrden mentioned, retain/release and objective-c memory management is a considerably large topic, one that has been extensively dealt with. I'd recommend reading this to get started and do some more research from there.
Though you can (should?) use ARC and save yourself some hassle, understanding the regular retain/release cycles will give you a better understanding of strong/weak references in ARC. While you don't have to understand everything about memory management in objective-c while using ARC, you still need to understand some of it.

Objective-C Proper Memory Management & Clean up with ARC

Coming from the world of managed memory, wondering what would be the proper way to clean up objects when using ARC.
For example: if declaring an instance variable in C#, .NET will allow the GC to pick it up once it leaves scope (method/loop body, etc)
What's the proper way to clean-up in Objective-C? Just set the reference/pointer to nil or call dealloc or will ARC detect that no external references are pointing to the instance once execution leaves scope and do the job for you?
ARC means "Automatic Reference Counting" and is just a way to let the compiler add the calls to retain/release/autorelease for you. It's not the same as GC but in most cases, you can consider that objects lifetime is automatically managed for you, like in GC.
If you want more information, you should read LLVM document on ARC
Last note: never call dealloc yourself. dealloc is the object's finalizer which is called once the ObjC runtime determines that the object reference count has reached 0. This method is only meant to be overriden by subclasses. In ARC mode, you generally don't need to do that, except if your object references non-object ivars that need to be finalized once the object itself is finalized.
will ARC detect that no external references are pointing to the
instance once execution leaves scope and do the job for you
Basically, yes, that's exactly what ARC will do. You don't need to clean up objects when you're using ARC; in fact, you can't (it stops you from trying to perform manual memory management).
You might want to consult the relevant discussion in my book:
http://www.apeth.com/iOSBook/ch12.html#_memory_management
It explains what's really happening behind the scenes (how memory is actually managed) and then goes on to describe how ARC shields you from most of it.
Note that (as I explain in the URL referenced above) it mostly isn't done by anything like garbage collection: it's done by inserting invisible explicit memory management throughout your code.
Well, in the past, iOS programmers were responsible for telling the system when they were done using an object that they allocated by sending the object a release message. That was done in accordance with a memory management system known as manual reference counting. As of Xcode 4.2, programmers no longer have to worry about this and can rely on the system to take care of releasing memory as necessary. This is done through a mechanism known as Automatic Reference Counting, or ARC for short. ARC is enabled by default when you compile new applications using Xcode 4.2 or later.
You can also disable ARC, in your Xcode interface, go to your main project (not main.h) your actual Xcode project, and select it, you should see a window in Xcode that displays the settings for your project, there will be one that says 'Objective-C Automatic Reference Counting' and it will be set to 'Yes', deactivate it (to 'No') and you shouldn't worry about the ARC, if you come from the world of data management and memory as you said, but keep in mind that it would be easier to you to keep updated to the iOS new features system, that are easier to the programmer to program, it just makes our life easier.
And now, the 'proper way to clean-up in Xcode' with ARC is with 'alloc' and 'init'.
With ARC in Xcode you do not need to worry for 'cleaning' that's the job of Xcode now, you just need to:
1) Create a variable.
2) Allocate.
3) Initialize.
That's it.
An example here:
int main (int argc, char * argv[])
{
#autoreleasepool {
Variable *myVariable;
// Create an instance of a Variable and initialize it
myVariable = [Variable alloc];
myVariable = [myVariable init];
// Set variable to 4/20
[myVariable setNumerator: 4];
[myVariable setDenominator: 20];
// Display the variable using the print method
NSLog (#"The value of myVariable is:");
[myVariable print];
}
return 0;
}
Just allocate and then initialize, yo do not need to do any thing else.
Keep in mind getters and setters.

blocks and ARC - copy or crash with release build (caused by optimization level)

I'm using Xcode 4.3.3 and developing for iOS 5.0+. In development of an ARC iOS application, I've started using blocks as a callback mechanism for asynchronous operations. The app works fine in the simulator and on the device.
Then I ran it the profiler for the first time, and it started crashing on me nearly right away - in particular, an EXC_BAD_ACCESS when trying to invoke the first callback block.
After a little investigation, it was clear the difference in behavior was because the profiler runs in "Release mode" by default - in particular, with Optimization Level set to "Fastest, Smallest [-Os]" instead of "None [-O0]".
For example, the following code (simplified for this question) would crash when trying to execute the callbackBlock:
- (void) setCallbackBlock:(void (^)(NSString *input))block
{
callbackBlock = block;
}
- (void) invokeCallbackWithInput:(NSString *)input
{
if (callbackBlock) {
callbackBlock(input);
}
}
Debugging into it, calling setCallbackBlock with optimization level set to "None", the incoming block would be an NSStackBlock, and the callbackBlock would become an NSMallocBlock.
However, with Optimization Level "Fastest, Smallest", it remained an NSStackBlock.
Changing the setter code to use [block copy] fixes the crashing problem (based on iOS 5 blocks crash only with Release Build).
However, another related question indicates that this shouldn't be necessary with ARC - block variables are copied to the heap in ARC - Why does Objective-C block still work without copying it to the heap?
So my question: What's going on here, and why? (Also, how can both of those answers be correct...?)
Edit:
To clarify how callbackBlock is being declared - just above my #implementation where those methods are is this:
#interface MyClass ()
{
void (^callbackBlock)(NSString *input);
}
#end
So my question: What's going on here, and why? (Also, how can both of those answers be correct...?)
I actually think the answer to the other question is wrong, in that it doesn't answer that particular question about blocks in ARC. The question is about passing a stack based block from one function/method to another. The answer is about something different, which is capturing __block variables within a block. That's a different issue.
The answer to your question is in the FAQ of the Transitioning to ARC Release Notes:
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.
So the way this works is that when you pass a block (in your case a block literal allocated on the stack), the compiler does not copy that block when it initializes the parameter for that call. The called function or method has the responsibility to copy that block itself if needed.
Where ARC does copy blocks automatically is when you are returning a block from a function or method. In that case, the compiler knows that it must do a copy to the heap for you, and so it does.
So your setter should be doing a block copy, even with ARC.
I hope that helps.
This is a long comment on Firoze's answer.
The document Automatic Reference Counting" section 7.5 states:
With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.
And this is the behavior I have seen.
So if callbackBlock is a strong instance variable then ARC should copy any stack-allocated block pass in block. I.e. the Debug version was correct and the Release version is a compiler bug.
If this is correct then you've found a compiler bug and should report it. Reporting it would not be bad either way, it should produce a definitive answer.

ARC, non-ARC, and inheritance

I haven't used ARC yet other than to deal with it when it forces it's way into a project via 3rd party code. I've read all the ARC docs but haven't seen an answer to this question:
If I have a class that's defined in a module compiled with -fobjc-arc, can I derive a new class from this in a module that is NOT ARC-enabled?
In my mind it should work fine as long as the derived class doesn't attempt to touch any ivars in the root class. It seems to me that even having a dealloc method that calls [super dealloc] would be fine in the derived class.
And, what about the other way around? Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
Bonus points: are there any gotcha's when mixing ARC and non-ARC code that I should make myself aware of?
There are no issues that I am aware of. You have to realize that ARC is something like a source code preprocessor, adding the memory management calls for you during the compilation. When you arrive at the linking phase, you can’t really tell ARC code from non-ARC code. (This is probably an over-simplification, but one that should work for your purposes.) If your derived class has correct memory management and the super class has correct memory management, the result will work fine.
About the only difference I can think of is handling of weak properties. But I don’t know enough about those to say if it’s possible to arrive at buggy code using some combination of ARC and MRC code with weak properties.
This was a comment, but having thought about it I want to expand what it said.
Have you tried inheriting an ARC class from a normal subclass? My thoughts (without having tried it either) is that this will not work. Firstly, if the ARC class has public properties or ivars using ARC keywords, like weak I think you will get errors during compilation from the header file. Secondly, I don't know how the dealloc would work. Do you need to call [super dealloc] or not? I don't know.
Anyway, if your superclass is ARC, why would you not use ARC in any subclasses? There's no advantage to doing that at all.
Can I derive a ARC-enabled class from a non-ARC class? Should work fine too, right?
I was going to say that won't work either, but I would have been wrong. Virtually everything has to inherit from NSObject which is manual reference counted.
Yes, you may both implement non-ARC ancestor from ARC parent class, and ARC ancestor from non-ARC parent class.
Actually, ARC is a syntax sugar, or you may say, is just preprocessor which analyzes your source code at compile step and inserts appropriate [release] and [retain] calls to your code. At runtime level nothing is changed (except for the weak properties).
ARC means the compiler takes care of memory management, non-ARC means you take care of it, but in both cases memory management works exactly the same way:
If an object must stay alive, its retain counter is increased (that's what retain does)
If an object is not needed anymore, its retain counter is decreased before the reference to it is lost (that's what release does)
If you are done with an object but it must not die yet, e.g. as you need to return it as a method result (and you don't want to return a dead object), it must be added to an autorelease pool that will decrease its retain count at a later time (that's what autorelease does, it's like saying "call release on that object at some future time.")
Newly created objects have a retain count of 1.
If the retain count reaches zero, the object is freed.
Whether you do all that yourself or the compiler does it for you, it plays no role. After compilation, these methods are being called, also with ARC, but with ARC the compiler has decided for you when which method is called. There is some extra magic, e.g. ARC doesn't always have to add objects to autorelease pools when returning them as method result, this can often be optimized away, but you don't have to care as this magic is only applied if the caller and the called method both are using ARC; if one of them isn't, then a normal autorelease is used (which still works in ARC exactly as it used to).
The only thing you must take care of is retain cycles. Whether you use ARC or not, reference counting can't deal with retain cycles. No difference here.
Pitfalls? Careful with Toll Free Bridging. A NSString * and a CFStringRef are in fact the same thing but ARC doesn't know about the CF-world, so while ARC takes care of the NSString, you must take care of the CFString. When using ARC, you need to tell ARC how to bridge.
CFStringRef cfstr = ...;
NSString * nsstr = (__bridge_transfer NSString *)cfstr;
// NSString * nsstr = [(NSString *)cfstr autorelease];
Code above means "ARC, please take ownership of that CFString object and take care of releasing it as soon as you are done with it". The code behaves like the code shown in the comment below; so careful, cfstr should have a retain count of at least one and ARC will release it at least once, just not yet. The other way round:
NSString * nsstr = ...;
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr;
// CFStringRef cfstr = (CFStringRef)[nsstr retain];
Code above means "ARC, please give me ownership of that NSString, I'll take care of releasing it once I'm done with it". Of course, you must keep that promise! At some time you will have to call CFRelease(cfstr) otherwise you will leak memory.
Finally there's (__bridge ...) which is just a type cast, no ownership is transferred. This kind of cast is dangerous as it can create dangling pointers if you try to keep the cast result around. Usually you use it when just feeding an ARC object to a function expecting a CF-object as ARC will for sure keep the object alive till the function returns, e.g. this is always safe:
doSomethingWithString((__bridge CFStringRef)nsstr);
Even if ARC was allowed to release nsstr at any time as no code below that line ever accesses it anymore, it will certainly not release it before this function has returned and function arguments are by definition only guaranteed to stay alive until the function returns (in case the function wants to keep the string alive, it must retain it and then ARC won't deallocate it after releasing it as the retain count won't become zero).
The thing most people seem to struggle with is passing ARC objects as void * context, as you sometimes have to with older API, yet that is in fact dead simple:
- (void)doIt {
NSDictionary myCallbackContext = ...;
[obj doSomethingWithCallbackSelector:#selector(iAmDone:)
context:(__bridge_retained void *)myCallbackContext
];
// Bridge cast above makes sure that ARC won't kill
// myCallbackContext prior to returning from this method.
// Think of:
// [obj doSomethingWithCallbackSelector:#selector(iAmDone:)
// context:(void *)[myCallbackContext retain]
// ];
}
// ...
- (void)iAmDone:(void *)context {
NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context;
// Use contextDict as you you like, ARC will release it
// prior to returning from this method. Think of:
// NSDictionary * contextDict = [(NSDictionary *)context autorelease];
}
And I have to real big gotcha for you that are not that obvious at first sight. Please consider this code:
#implementation SomeObject {
id _someIVAR;
}
- (void)someMethod {
id someValue = ...;
_someIVAR = someValue;
}
This code is not the same in ARC and non ARC. In ARC all variables are strong by default, so in ARC this code behaves just like this code would have:
#interface SomeObject
#property (retain,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Assigning someValue will retain it, the object stays alive! In non-ARC the code will behave like this one:
#interface SomeObject
#property (assign,nonatomic) id someIVAR;
#end
#implementation SomeObject
- (void)someMethod {
id someValue = ...;
self.someIVAR = someValue;
}
Note the property is different, as ivar's in non-ARC are neither strong or weak, they are nothing, they are just pointers (in ARC that is called __unsafe_unretained and the keyword here is unsafe).
So if you have code that uses ivars directly and doesn't use properties with setters/getters to access them, then switching from non-ARC to ARC can cause retain cycles in code that used to have sane memory management. On the other hand, moving from ARC to non-ARC, code like that can cause dangling pointers (pointers to former objects but since the object has already died, these point to nowhere and using them has unpredictable results), as objects that used to be kept alive before may now die unexpectedly.

Memory management in Objective-C

#import <Foundation/Foundation.h>
int main (int argc, char const *argv[])
{
SampClass *obj=[[SampClass alloc] init];
[obj release];
NSLog(#"%i", [obj retainCount]);
return 0;
}
Why does this give retainCount of 1, when it should be 0
Do not call retainCount.
Not even in debugging code. And especially not when you are trying to learn how Cocoa's memory management works.
The absolute retain count of an object is not something under your control. Often, the value will be quite unexpected. There may be any number of caches, static allocations (like constant NSStrings), or other internal implementation details within frameworks that make an object's retain count other than what you expect.
The retain count of objects should be thought of entirely in terms of deltas. If you cause the retain count to increase, you must decrease it somewhere if you want the object to be deallocated. Period. End of story.
Trying to think of retain counts in absolute terms will just lead to confusion and wasted hours.
The Cocoa Memory Management Guide explains this rather well.
There's no question of what retainCount should be in your code, you shouldn't be calling it. Relying on the result of messaging a deallocated object is not a good idea. Here's what happens when I copy your code, and run it with one of the (numerous) retain-count-debugging features of the frameworks:
heimdall:~ leeg$ pbpaste | sed s/SampClass/NSObject/g > fubar.m
heimdall:~ leeg$ cc -o fubar -framework Foundation fubar.m
heimdall:~ leeg$ NSZombieEnabled=YES ./fubar
2010-01-07 13:40:10.477 fubar[871:903] *** -[NSObject retainCount]: message sent to deallocated instance 0x10010d8f0
Trace/BPT trap
Because the object has been deallocated before your NSLog call.
I assume that release is implemented something like the following:
if(retainCount==1) [self dealloc];
else retainCount--;
and you are accessing the deallocated object illegally.
Update:
Found these questions whose answers should enlighten you further:
here and here.
The object is being dealloced but once the object goes to retain count 0 any method calls are likely to return stale values.
If you compile and run on 32 bit, you will get an error (message retainCount sent to freed object=0x...).
I'm guessing the 64bit runtime (default compile option on Leopard) does not collect objects as aggressively as the 32 bit runtime so your call to retainCount does not cause an error.
To check that you object is indeed dealloced, implement dealloc for your SampClass:
- (void) dealloc
{
NSLog(#"Dealloc");
[super dealloc];
}
Later edit: As I suspected, the difference in behavior between 32 and 64 bit when calling a method on a released object is from the runtime and not undefined behavior.
In 32 bit, once a class is freed it's isa pointer is switched to a special class that allows intercepting messages to freed objects. This does not happen in 64 bit.
Relevant source is objc-class.m:
#if !__OBJC2__
// only clobber isa for non-gc
anObject->isa = _objc_getFreedObjectClass ();
#endif