unload dynamic library needs two dlclose() calls? - objective-c

I have a dynamic library which I load using dlopen() and then unload using dlclose();
If I dont include any objective c code dlopen() needs one dlclose() call which is expected behavior. But when I include any objective c code to target, I have problem that I need to do two dlclose() calls to the loaded library in order to unload.
Is this something expected behavior? How can I fix it?

I realize that you are using dlopen, not CFBundle or NSBundle. Nevertheless, the Code Loading Programming Topics manual says this:
In Cocoa applications, you should not use CFBundle routines to load and unload executable code, because CFBundle does not natively support the Objective-C runtime. NSBundle correctly loads Objective-C symbols into the runtime system, but there is no way to unload Cocoa bundles once loaded due to a runtime limitation.
and this:
Because of a limitation in the Objective-C runtime system, NSBundle cannot unload executable code.
This makes me suspect that when you load your library, it registers itself with the Objective-C runtime, and the runtime calls dlopen on the library again (or somehow increases the library's reference count).
I searched the Objective-C runtime source code and found this:
// dylibs are not allowed to unload
// ...except those with image_info and nothing else (5359412)
if (result->mhdr->filetype == MH_DYLIB && _hasObjcContents(result)) {
dlopen(result->os.dl_info.dli_fname, RTLD_NOLOAD);
}
So yes, the Objective-C runtime is calling dlopen on your library specifically to prevent it from being unloaded. If you cheat and call dlclose twice, you should expect bad things to happen.

Related

Can a dynamic library reference Objective-C objects and still be unloaded?

I know that, at least on OS X, due to the way classes are loaded by Apple's Objective-C runtime it is not possible to dynamically unload a dynamic library that contains the implementations of a loaded class. Does this hold true for a library that only knows about objects from referencing a header, but does not contain the method implementations of any class?
For clarity, I'd like to use Objective-C to write the dynamic library, but would load and unload functions with signatures like ResultObject* performActionOnObject(SomeObject* object).
Edit:
For more clarity, consider a function like
NSNumber* computeFactorial(NSNumber* operand){
NSUInteger n = [operand unsignedIntegerValue];
/// ... pure C loop omitted
return [NSNumber numberWithUnsignedInteger:n];
}
And assume when it is called an autorelease pool is active. Would that be okay to unload?
If the client references your class directly, it will result in a linker error if the class is not in a linked binary. You could load/unload classes at runtime, but you would need to look them up by their names (strings) to use them. You will also need to register the class(es) before you look them up by name.
You can pass C functions to runtime calls like class_addMethod and method_exchangeImplementations to extend/alter your ObjC class at runtime.
Googling "method swizzling" will lead you to examples.
So ultimately… "It depends on how you interface with the object".

How to programmatically detect automatic reference counting?

This might be a silly question, but I just wanted to know. I want my code to detect if ARC is enabled, programmatically. How do I do that? Is there is any flag that I could check? Actually the problem is that, I have written an open-source library. I have used release and retain in it. if some one else uses my library files using ARC enabled, I dont want them to get any errors. how do I achieve this? or is there any possible ways I can provide any tools to compile my library before using it?
#if !__has_feature(objc_arc)
//Do manual memory management...
#else
//Usually do nothing...
#endif
This is of course a compile-time check, you cannot check for ARC at runtime.
An alternative would be to set the -fno-objc-arc compiler flag for your files that use manual memory management in a project that otherwise uses ARC.
Whether you want to bother with this at all or just use ARC everywhere depends on how backward-compatible you want/need to be. Code that supports both ARC and MRC can get quite hard to read and maintain.
You don't detect it programmatically, it operates based on translations. That is, it is not like Garbage Collection -- which is process-wide, required all linked libraries to support (and implement it correctly in that mode). You can have some files compiled with ARC, and some without.
However, you can detect it at compilation.
As far as the distribution of your library: I would not bother with a translation based system, where ref count ops are conditionally enabled. I would (personally) just support one model (MRC in your case, until you choose to migrate it to ARC), then expect people to link to the library, or if they compile it in a target they configure, to disable ARC. Conditionally enabling/disabling code based on the presence of a feature is asking for tough bugs, particularly when it's likely to affect 9% of your library's lines of code.
NO, you can't, Xcode would not compile in ARC projects if your source uses retain-release

ARC error when compiling

I'm trying to compile using the LLVM GCC 4.0 compiler, and I get this error in multiple of my .m files: ARC forbids explicit message send of 'release'
I've tried using -fno-objc-arc as a compiler flag but that returns the error: Unrecognized command line option "-fno-objc-arc".
How can I solve this?
Simply remove all calls to -release. You're not allowed to call -release under ARC because the compiler will insert all the necessary retain/release calls for you. Read more about ARC here.
The other way is to use the conversion tool, and Xcode can convert your project to ARC (including removing these calls) for you:
To disable ARC entirely, change your build settings:
However I'd recommend you start using ARC, it will make things a lot easier and actually faster too.
If you happen to be using the ASI (http://allseeing-i.com/ASIHTTPRequest/How-to-use) api, refer to this answer as it needs to be built using -fno-obj-arc flags for specific classes... Files doesn't support the ARC feature, how to deal with and refer to the answer titled 'Disable ARC for that one class'

Objective-C : Properties question

As far as I understand when you use properties the compiler still converts them to accessor methods during compilation. I got a little irritated when I read you need OSX 10.5 or later to use properties. Why is that so?
If in the compiled application are in fact still accessor methods I see no need for OSX 10.5. Or is there something else going on during run-time?
Because the Objective-C 2.0 runtime was not back ported to 10.4. You need compiler and runtime support to handle all of ObjC 2.0 properly.

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.