Working with the Objective-C/Cocoa flat namespace
I've not found anything that addresses my specific name space question as yet.
I am working on some AudioUnit plug-ins featuring Cocoa based GUIs. The plug-ins use a common library of user interface classes (sliders, buttons etc) which are simply added to each Xcode project.
When I recompile and distribute updates it is pretty much guaranteed that at least one user interface class will have been updated since the last release. If the user launches an older plug-in before an updated plug-in then the old Cocoa classes are already loaded into the run time and the plug-in attempts to use the older implementations - often resulting in a failure one way or another.
I know frameworks are the intended solution but the overhead and backwards compatibility issues are not ideal. I prefix all class names where possible but what options do I have to ensure that each plug-in contains unique class names for the shared user interface classes?
Update:
The solution I seem to be arriving at is as follows:
Set a preprocessor compiler flag开发者_JAVA技巧 e.g.
OBJC_PREFIX=1
.Create a header file to contain all the class name redefinitions and conditionally include it in the header of each class you want to 'rename' e.g:
#ifdef OBJC_PREFIX #include "CocoaPrefixHeader.h" #endif @interface MySlider : ... etc
Fill the header file (in this case CocoaPrefixHeader) with something like the following:
#define MySlider Prefix_MySlider #define MyButton Prefix_MyButton
Using ibtool convert all your class names in an existing nib/xib file to the new names e.g:
ibtool --convert MySlider-Prefix_MySlider nibfile.xib --write nibfile2.xib ibtool --convert MyButton-Prefix_MyButton nibfile2.xib --write nibfile2.xib
This last step converts all class names and outlets etc in the nib file. Once converted you can edit the nib as normal and IB keeps track of the redefined names.
This process is tedious and laborious but it is working for me. Far better to cater for it at the outset.
In your pre-compiled header (.pch) file for each plug-in, you can #define
the classes to have different names, e.g.:
#define ClassNameUsedInYourCode ClassNameCompiledInThisProject
#define WidgetButton WahWahPedalPluginWidgetButton
As long as you're creating your UI programmatically, this will ensure that the class names are unique per-plugin. Unfortunately this won't work if you have class names baked into nib files.
In that case, you'd probably need to have some sort of pre-processing script that runs before compilation and replaces any instances of the shared class names with the project-specific class names in all files in the project, including the .xib files. This could get pretty messy but I can't see too many options.
I had a similar issue. I needed to have more than one version of the same bundle running in the same application space at the same time (I can't even remember why). It was not easy, I discussed my problems and options on the Objective-C mailing list. In the end, I modified the build-environment to:
- Scan every header for classes declared with
@interface
. - Create a new header filled with only preprocessor macros that redefine classnames from
MyClass
toMyClass_v1_00
(or whatever version was defined by the Info.plist file). This header was calledClassRenamer.h
. - As an intermediate build step, parse all xib XML files and replace references of
MyClass
toMyClass_v1_00
. This doesn't modify the original xib files, which is handy. - Modify the command-line build flags to include
ClassRenamer.h
for all.m
files.
Surprisingly, everything works perfectly, both at runtime and even in the debugger. If I put a breakpoint on a particular line, it breaks on any version of the class that is loaded, and Xcode even shows the class's name as MyClass_v1_00
. The biggest concern is code that looks up classes by name, i.e. using NSClassFromString
.
Whilst the solution I arrived at in the updated part of the question works as the final step in a project I can't recommend it for anything where your classes are in a state of flux. I was unable to add additional outlets to classes and have them show up in IB, for example.
In the end I just duplicated my classes and added unique name prefixes for different projects. Using ibtool --convert to update the xib file made this process a lot faster.
Once things settle down maybe a framework will be a better idea.
精彩评论