storing objects in stl containers in a garbage collect environment - objective-c

I have a Mac OS X App that I need to store objective-c objects in stl containers (as pointers). Everything works fine until I compile the program with garbage collection "supported" due to a custom framework that I need to use.
Problem is all the objects that get stored in the stl containers get released. Is there a way to tell the compiler to not collect those away and I'll release them when I'm done with them?
Is this possible? Is there a way to have a framework that uses garbage collection and the main program doesn't? That would also solve my problem. I can recompile the framework, but it heavily relies on GC.

You can disable garbage collection for individual objects using NSGarbageCollector's disableCollectorForPointer: method. It will then hang around until you call -enableCollectorForPointer: on it.
I believe (but I'm not totally sure) you can also use CFRetain/CFRelease on NSObject subclasses for more or less the same effect.

Related

Can I snapshot and restore memory of Objective-C object graph?

I'm designing a object persistent code.
IMO, memory snapshot is fastest, reliable and compact persistent method within a few limitation.
It's easy with C structs. I can layout all objects' memory layout manually. I can save all references as index of object collection. So reference is not a problem.
Anyway I want to try this with Objective-C objects. To do this, objects must be positioned in specific location of memory. So, if I can specify memory location of allocation, I can snapshot the memory. And when restoring, I can get an object at specific address.
Of course, all of these are machine-specific and needs many tricks, but it's fine to me.
The only problem is I don't know way to specify location of new Objective-C object. How can I do this?
Generally people use NSCoding and NSKeyedArchiver (or some custom subclass thereof). I think your C method would have worked before the 64-bit runtime, since the data part of objects was implemented using structs, but I think the new runtime's use of nonfragile instance variables would complicate matters. In any event, the program that loads the persistent objects still has to have the class definitions for them, either hard-coded or loaded via bundles.

As a new Objective-C developer, what memory-related issues should I watch out for using ARC?

Recently I've begun to code in Objective-C for iOS 5 devices. My brand new MacBook is loaded with Xcode 4.2 and the latest Mac & iOS SDKs. So far it's been a fun experience but there is one problem that I see with the current state of documentation and available books.
Specifically, most books (that have yet to be updated) always reference how and when to manage your memory. This is great, however, the current SDK/compiler includes Automatic Reference Counting and since I leave this turned on for my projects, I have no clue as to what I should personally monitor and manage myself.
I come from a C# background. Memory management in C# (technically, .NET) is entirely handled by the framework garbage collector. I understand that ARC is actually a compiler feature that automatically adds boiler-plate code where it belongs. Furthermore, my attempts to try and discover where I should manage my own releasing of objects has caused nothing but compiler errors because ARC wants to take care of it for me.
I have yet to find a case where I've needed to manage my objects. I am becoming "lazy" because I don't know what to monitor and release myself and I am completely oblivious about how this behavior could affect the performance of my application.
In new-user terms, what "gotchas" should I be aware of while using ARC in my iOS projects? I've read a few questions regarding memory management and ARC around here but, to be honest, they are not to friendly to the new iOS developer. Could someone please give a reasonable, bullet-point list that explains what problems and issues to watch out for, as well as a fair guide as to when self-management of memory is necessary?
Circular References. When objects are codependent, they will leak. You will need to mark some references as weak, and Instruments can help you locate these references. These leaks won't even show up as leaks because they hold strong references to each other.
Create Autorelease Pools #autorelease to keep autorelease pool sizes down where you create many autoreleased objects (directly or indirectly). Specifically, your program and programs you depend on will autorelease many objects (ARC or otherwise). An autoreleased object is one which will be released "in the future". Every Cocoa program expects an autorelease pool to exist on each thread. This is why you create a new pool when you create a new thread, and why you create one in main. The pools operate as a stack - you may push and pop pools. When a pool is destroyed it sends its deferred release message to every object it holds. This means that really large loops with many temporary allocations may result in many objects which are referenced only by the pool, and the pool may grow very large. For this reason, you drain manage pools directly in some cases to minimize the number of objects that are waiting to be released and deallocated.
Use proper bridging/casting. Sometimes you will need to manage lifetimes explicitly. ARC handles the obvious cases, but there are complex cases where you will need to manage lifetimes explicitly.
When using malloc'ed and new'ed allocations, as well as opaque types in 'Core' APIs. ARC only manages NSObject types. You still need to explicitly free, delete, and use correct ref counting for these allocations, types, and when interfacing with those APIs.
Always follow NS-API naming conventions, and avoid explicit memory management attributes where possible.
You'll obviously need MRC when you compile sources without ARC or GC. This is quite common when using/working with other libraries/code bodies. Of course, the compiler handles interactions correctly so your ARC program should not leak.
ARC handles most of what you will need if you use proper naming and written style, but there will be a few other corner cases. Fortunately, you can still run Leaks and Zombies to locate these issues if you don't realize them during development.

Reference-counting caveats in Objective-C?

I've long considered myself a garbage collection snob – despite a secret love for C++, I find myself sneering at developers who actively choose to use languages without (read: missing) garbage collection when they're given the option.
And then I met Objective-C. Wow! Its system of reference counting seems brilliantly simple – I'd even go so far as to say elegant. When developing for OSX, developers are given the option to use a snazzy GC; when developing for iOS, developers are stuck with reference counting.
My question is:
If I am developing an OSX application that could potentially be ported to iOS, is Objective-C's reference counting system time-consuming enough (development-wise and bug-fixing-wise) to warrant ignoring it for the application's first version?
What problems am I likely to run into if I rely on reference counting*, assuming I'm not clever enough to construct any diabolically complex cyclical data structures? With features like autorelease, it all seems so easy, but I know that Apple wouldn't have invested the effort into creating a garbage collector if this were really the case. What should I be on the lookout for?
* I am aware that I can use the garbage collector even if I am throwing around retains and releases (they'll be ignored). However, considering non-GC applications often use RAII, I don't understand how that would work if a generational GC were to "replace" calls to retain and release. Wouldn't resources potentially be released late?
My experience with developing code to port to iOS is that taking GC only code and back porting it to reference counting is a bit tedious and time consuming and potentially error prone. Having said that, as long as you use properties (make them retain even though it makes no difference in GC) as much as possible and you enable the static analyser build phase, it's not too bad. The static analyser will catch most failures to observe the memory management rules. It won't notice if you fail to release an ivar in dealloc, but you can go through and systematically add all the dealloc methods.
Bear in mind that you can't directly port a Mac application to the iPhone, the VC part of MVC has to be completely rewritten, so you could take the approach of writing the Mac UI solely for garbage collection and only make the model classes compatible with both GC and reference counting.

Mixing garbage collected framework with normal code

I know my way around Objective-C and I have experience with garbage collection from .NET, although I never used it in objective-c. I write my code without using it.
Now I'm thinkig about using one of the frameworks (Blocks) which is available as GC-only. My question is - can I still use the framework without any changes to my current non-GC code and without using GC myself?
A process is either GC or non-GC. That is, all Objective-C will either always be GC'd or will never be GC'd. There is no mixing of the two memory models in a single process. You cannot mix a GC only framework with a non-GC only framework.
When building a framework, you can set GC to "supported" at which point in time the framework could be used in either a GC'd or a non-GC'd process. However, you will have to maintain correctness for both running environments separately.
What is this "Blocks" framework to which you refer? If you are talking about Blocks, the language feature shipped in Snow Leopard's Objective-C, then it works just fine under both GC and non-GC.
As stated in the garbage collection programming guide, "Code compiled as GC Required is presumed to not use traditional Cocoa retain/release methods and may not be loaded into an application that is not running with garbage collection enabled."
So no, unfortunately. But how much work it would be to adopt garbage collection depends on your app. You might try testing to see if it looks like a big project. (It often is, but sometimes it's not so bad.)
In project settings, you can compile with GC supported (NOT required) and they should mix just fine. Compiling with GC supported but not required should allow retain/release to work alongside GC
If you can't compile the project with GC supported, then you'll be in trouble.
EDIT: To clarify: If you compile your project with GC required (-fobjc-gc-only) your retain/release code will be ignored. If you compile without any regard for GC, you can't use the GC framework. However, if you compile with GC supported (-fobjc-gc), your retain/release code will function as needed, and the GC framework will also work.
EDIT: To further clarify (I'm really tired today): If you include a GC-only framework, you have to compile with -fobjc-gc or -fobjc-gc-only and run with garbage collection, in which case your retain/release statements will indeed be no-ops. However, if you compile with -fobjc-gc-only and try to include a framework that is not build with any GC support, you'll have issues. Whereas my understanding is if you compile with -fobjc-gc, you can include a GC-only framework as well as a non-GC framework. From the docs I linked above:
Code compiled as GC Supported is
presumed to also contain traditional
retain/release method logic and can be
loaded into any application.
So if you wanted your Framework to play nice with anything, you'd be better served to compile with -fobjc-gc instead of -fobjc-gc-only.
Apparently I was having a hard time getting my thoughts to the keyboard yesterday. According to the docs:
-fobjc-gc-only This means that only GC logic is present. Code compiled as GC
Required is presumed to not use
traditional Cocoa retain/release
methods and may not be loaded into an
application that is not running with
garbage collection enabled.
So if you build your framework with GC Required, you can't load it into a non-GC-enabled application.
Also according to the docs:
-fobjc-gc This means that both GC and retain/release logic is present. Code
compiled as GC Supported is presumed
to also contain traditional
retain/release method logic and can be
loaded into any application.
So while the burden is on the developer to include retain/release logic in a project that is compiled GC Supported, this allows a framework to be loaded in any application.
I apologize for my unclear rambling yesterday. I was running on 3 hours sleep and trying to do several things at once. Never a good idea.

Avoiding, finding and removing memory leaks in Cocoa

Memory (and resource) leaks happen. How do you make sure they don't?
What tips & techniques would you suggest to help avoid creating memory leaks in first place?
Once you have an application that is leaking how do you track down the source of leaks?
(Oh and please avoid the "just use GC" answer. Until the iPhone supports GC this isn't a valid answer, and even then - it is possible to leak resources and memory on GC)
In XCode 4.5, use the built in Static Analyzer.
In versions of XCode prior to 3.3, you might have to download the static analyzer. These links show you how:
Use the LLVM/Clang Static Analyzer
To avoid creating memory leaks in the first place, use the Clang Static Analyzer to -- unsurprisingly -- analyse your C and Objective-C code (no C++ yet) on Mac OS X 10.5. It's trivial to install and use:
Download the latest version from this page.
From the command-line, cd to your project directory.
Execute scan-build -k -V xcodebuild.
(There are some additional constraints etc., in particular you should analyze a project in its "Debug" configuration -- see http://clang.llvm.org/StaticAnalysisUsage.html for details -- the but that's more-or-less what it boils down to.)
The analyser then produces a set of web pages for you that shows likely memory management and other basic problems that the compiler is unable to detect.
If your project does not target Mac OS X desktop, there are a couple of other details:
Set the Base SDK for All Configurations to an SDK that uses the Mac OS X desktop frameworks...
Set the Command Line Build to use the Debug configuration.
(This is largely the same answer as to this question.)
Don't overthink memory management
For some reason, many developers (especially early on) make memory management more difficult for themselves than it ever need be, frequently by overthinking the problem or imagining it to be more complicated than it is.
The fundamental rules are very simple. You should concentrate just on following those. Don't worry about what other objects might do, or what the retain count is of your object. Trust that everyone else is abiding by the same contract and it will all Just Work.
In particular, I'll reiterate the point about not worrying about the retain count of your objects. The retain count itself may be misleading for various reasons. If you find yourself logging the retain count of an object, you're almost certainly heading down the wrong path. Step back and ask yourself, are you following the fundamental rules?
Always use accessor methods; declare accessors using properties
You make life much simpler for yourself if you always use accessor methods to assign values to instance variables (except in init* and dealloc methods). Apart from ensuring that any side-effects (such as KVO change notifications) are properly triggered, it makes it much less likely that you'll suffer a copy-and-paste or some other logic error than if you sprinkle your code with retains and releases.
When declaring accessors, you should always use the Objective-C 2 properties feature. The property declarations make the memory management semantics of the accessors explicit. They also provide an easy way for you to cross-check with your dealloc method to make sure that you have released all the properties you declared as retain or copy.
The Instruments Leaks tool is pretty good at finding a certain class of memory leak. Just use "Start with Performance Tool" / "Leaks" menu item to automatically run your application through this tool. Works for Mac OS X and iPhone (simulator or device).
The Leaks tool helps you find sources of leaks, but doesn't help so much tracking down the where the leaked memory is being retained.
Follow the rules for retaining and releasing (or use Garbage Collection). They're summarized here.
Use Instruments to track down leaks. You can run an application under Instruments by using Build > Start With Performance Tool in Xcode.
I remember using a tool by Omni a while back when I was trying to track down some memory leaks that would show all retain/release/autorelease calls on an object. I think it showed stack traces for the allocation as well as all retains and releases on the object.
http://www.omnigroup.com/developer/omniobjectmeter/
First of all, it's vitally important that your use of [ ] and { } brackets and braces match the universal standard. OK, just kiddin'.
When looking at leaks, you can assume that the leak is due to a problem in your code but that's not 100% of the fault. In some cases, there may be something happening in Apple's (gasp!) code that is at fault. And it may be something that's hard to find, because it doesn't show up as cocoa objects being allocated. I've reported leak bugs to Apple in the past.
Leaks are sometimes hard to find because the clues you find (e.g. hundreds of strings leaked) may happen not because those objects directly responsible for the strings are leaking, but because something is leaking that object. Often you have to dig through the leaves and branches of a leaking 'tree' in order to find the 'root' of the problem.
Prevention: One of my main rules is to really, really, really avoid ever allocating an object without just autoreleasing it right there on the spot. Anywhere that you alloc/init an object and then release it later on down in the block of code is an opportunity for you to make a mistake. Either you forget to release it, or you throw an exception so that the release never gets called, or you put a 'return' statement for early exit somewhere in the method (something I try to avoid also).
You can build the beta port of Valgrind from here: http://www.sealiesoftware.com/valgrind/
It's far more useful than any static analysis, but doesn't have any special Cocoa support yet that I know of.
Obviously you need to understand the basic memory management concepts to begin with. But in terms of chasing down leaks, I highly recommend reading this tutorial on using the Leaks mode in Instruments.