Effective Objective-C 2.0:Item 15: Use Prefix Names to Avoid Namespace Clashes

原创 2013年12月06日 11:59:16

可惜没有指出怎么改第三方library名字的具体操作

找了下资料,觉得下面这个应该靠谱,没试验过~~ 用到时侯再研究
http://stackoverflow.com/questions/6940384/how-to-deal-with-symbol-collisions-between-statically-linked-libraries/6940389#6940389


Item 15: Use Prefix Names to Avoid Namespace Clashes

Unlike other languages, Objective-C has no built-in namespace feature. For this reason, it is easy for names to clash unless measures are taken to avoid the potential. The impact a naming clash has on an application is that it may not link, owing to duplicate symbol errors like this:

duplicate symbol _OBJC_METACLASS_$_EOCTheClass in:
    build/something.o
    build/something_else.o
duplicate symbol _OBJC_CLASS_$_EOCTheClass in:
    build/something.o
    build/something_else.o

This error results because the symbol for the class and metaclass (seeItem 14) symbols for a class called EOCTheClass have been defined twice, from two implementations of a class called EOCTheClass in twoseparate parts of the application’s code, perhaps from two separate libraries that you are pulling in.

Even worse than not linking would be if one of the libraries that contained one of the duplicates were loaded at runtime. In this case, the dynamic loader would encounter the duplicate symbol error and most likely bring down the entire application.

The only way to avoid this problem is to use a crude form of namespacing: prefixing all your names with a certain prefix. The prefix you choose should be relevant to your company, application, or both.For example, if your company were named Effective Widgets, you might decide to use the prefix EWS for code common to all your applications and EWB for code just for the application called Effective Browser. It’s still not impossible to have clashes when you prefix your names, but it is much less likely.

If you are creating applications using Cocoa, it is important to note that Apple has stated that it reserves the right to use all two-letter prefixes, so you should definitely choose a three-letter prefix in this case. For example, an issue could have arisen by not following these guidelines and deciding to use the TW prefix. When the iOS 5.0 SDK came out, it brought along the Twitter framework, which too uses theTW prefix, which has a class called TWRequest for making HTTP requests to the Twitter API. You could very easily also have had a class called TWRequest if you had an API of your own, for a company called Tiny Widgets, for example.

The prefixing should not stop with class names but should apply to all names that you have within your application. Item 25 explains the importance of prefixing category names and the methods within them if the category is on an existing class. Another important and often overlooked potential for conflict is pure C functions or global variables you use within the implementation files of your classes. It’s often easy to forget that these will appear as top-level symbols within your compiled object files. For example, the AudioToolbox framework in the iOS SDK has a function for playing a sound file. You can give it a callback that gets called when it finishes. You might decide to write a class to wrap this up into an Objective-C class that calls a delegate when the sound file finishes, like so:

// EOCSoundPlayer.h
#import <Foundation/Foundation.h>

@class EOCSoundPlayer;
@protocol EOCSoundPlayerDelegate <NSObject>
- (void)soundPlayerDidFinish:(EOCSoundPlayer*)player;
@end

@interface EOCSoundPlayer : NSObject
@property (nonatomic, weak) id <EOCSoundPlayerDelegate> delegate;
- (id)initWithURL:(NSURL*)url;
- (void)playSound;
@end

// EOCSoundPlayer.m
#import "EOCSoundPlayer.h"
#import <AudioToolbox/AudioToolbox.h>

void completion(SystemSoundID ssID, void *clientData) {
    EOCSoundPlayer *player =
        (__bridge EOCSoundPlayer*)clientData;
    if ([player.delegate
            respondsToSelector:@selector(soundPlayerDidFinish:)])
    {
        [player.delegate soundPlayerDidFinish:player];
    }
}

@implementation EOCSoundPlayer {
    SystemSoundID _systemSoundID;
}

- (id)initWithURL:(NSURL*)url {
    if ((self = [super init])) {
        AudioServicesCreateSystemSoundID((__bridge CFURLRef)url,
                                         &_systemSoundID);
    }
    return self;
}

- (void)dealloc {
    AudioServicesDisposeSystemSoundID(_systemSoundID);
}

- (void)playSound {
    AudioServicesAddSystemSoundCompletion(
        _systemSoundID,
        NULL,
        NULL,
        completion,
        (__bridge void*)self);
    AudioServicesPlaySystemSound(_systemSoundID);
}

@end

This looks completely innocuous, but looking at the symbol table for the object file created from this class, we find the following:

00000230 t -[EOCSoundPlayer .cxx_destruct]
0000014c t -[EOCSoundPlayer dealloc]
000001e0 t -[EOCSoundPlayer delegate]
0000009c t -[EOCSoundPlayer initWithURL:]
00000198 t -[EOCSoundPlayer playSound]
00000208 t -[EOCSoundPlayer setDelegate:]
00000b88 S _OBJC_CLASS_$_EOCSoundPlayer
00000bb8 S _OBJC_IVAR_$_EOCSoundPlayer._delegate
00000bb4 S _OBJC_IVAR_$_EOCSoundPlayer._systemSoundID
00000b9c S _OBJC_METACLASS_$_EOCSoundPlayer
00000000 T _completion
00000bf8 s l_OBJC_$_INSTANCE_METHODS_EOCSoundPlayer
00000c48 s l_OBJC_$_INSTANCE_VARIABLES_EOCSoundPlayer
00000c78 s l_OBJC_$_PROP_LIST_EOCSoundPlayer
00000c88 s l_OBJC_CLASS_RO_$_EOCSoundPlayer
00000bd0 s l_OBJC_METACLASS_RO_$_EOCSoundPlayer

Note the symbol lurking in the middle, called _completion. This is the completion function created to handle when the sound has finished playing. Even though it’s defined in your implementation file and not declared in the header file, it still appears as a top-level symbol like this. Thus, if another function called completion is created somewhere, you’ll end up with a duplicate-symbol error when linking, such as the following:

duplicate symbol _completion in:
    build/EOCSoundPlayer.o
    build/EOCAnotherClass.o

Worse still would be if you were shipping your code as a library for others to use in their own applications. If you exposed a symbol called_completion like this, anyone using your library would not be able to create a function called completion, which is a nasty thing for you to do.

So you should always prefix C functions like this as well. In the preceding example, you could call the completion handlerEOCSoundPlayerCompletion, for example. This also has the side effect that if the symbol ever appears in a backtrace, it’s easy to determine what code the problem has come from.

You should be particularly careful of the duplicate-symbol problems when you use third-party libraries and ship your code as a library that others plug into their own applications. If the third-party libraries that you use are also going to be used by the application, it’s easy for duplicate-symbol errors to arise. In that case, it’s common to edit all the code of the libraries you use to prefix them with your own prefix.For example, if your library is called EOCLibrary and you pull in a library called XYZLibrary, you would go through and prefix all names in XYZLibrary with EOC. The application is then free to useXYZLibrary itself, without the chance of a naming collision, as shown in Figure 3.1.

Image

Figure 3.1 Avoiding naming clashes where a third-party library is included twice: once by the application itself and once by another library

Going through and changing all the names might seem like a rather tedious thing to do, but it’s prudent if you want to avoid naming collisions. You may ask why it’s necessary to do this at all and why the application can’t simply not include XYZLibrary itself and use your implementation of it. It’s possible to do that as well, but consider the scenario in which the application pulls in a third library, ABCLibrary, that has also decided to use XYZLibrary. In that case, if you and the author of ABCLibrary hadn’t prefixed, the application would still get duplicate-symbol errors. Or if you use version X of XYZLibrary but the application requires features from version Y, it would want its own copy anyway. If you spend time using popular third-party libraries with iOS development, you will frequently see this kind of prefixing.

Things to Remember

Image Choose a class prefix that befits your company, application, or both. Then stick with that prefix throughout.

Image If you use a third-party library as a dependency of your own library, consider prefixing its names with your own prefix.

Effective Objective-C 2.0:Item 25: Always Prefix Category Names on Third-Party Classes

Item 25: Always Prefix Category Names on Third-Party Classes Categories are commonly used to add ...

Effective Objective-C 2.0:Item 20: Prefix Private Method Names

Item 20: Prefix Private Method Names It’s extremely common for a class to do much more than it ap...

Effective Objective-C 2.0: Item 35: Use Zombies to Help Debug Memory-Management Problems

Item 35: Use Zombies to Help Debug Memory-Management Problems Debugging memory-management issues ...

Effective Objective-C 2.0: Item 39: Use Handler Blocks to Reduce Code Separation

Item 39: Use Handler Blocks to Reduce Code Separation A common paradigm in programming a user int...

Effective Objective-C 2.0: Item 30: Use ARC to Make Reference Counting Easier

Item 30: Use ARC to Make Reference Counting Easier Reference counting is a fairly easy concept to...

Effective Objective-C 2.0:Item 26: Avoid Properties in Categories

Item 26: Avoid Properties in Categories A property is a way of encapsulating data (see Item 6)....

Effective Objective-C 2.0: Item 43: Know When to Use GCD and When to Use Operation Queues

Item 43: Know When to Use GCD and When to Use Operation Queues GCD is a fantastic technology, but...

Effective Objective-C 2.0:Item 50: Use NSCache Instead of NSDictionary for Caches

Item 50: Use NSCache Instead of NSDictionary for Caches A common problem encountered when develop...

Effective Objective-C 2.0: Item 45: Use dispatch_once for Thread-Safe Single-Time Code Execution

Item 45: Use dispatch_once for Thread-Safe Single-Time Code Execution The Singleton design pattern—...

Effective Objective-C 2.0: Item 41: Prefer Dispatch Queues to Locks for Synchronization

Item 41: Prefer Dispatch Queues to Locks for Synchronization Sometimes in Objective-C, you will com...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Effective Objective-C 2.0:Item 15: Use Prefix Names to Avoid Namespace Clashes
举报原因:
原因补充:

(最多只允许输入30个字)