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 functionality to an existing class for which you don’t own the source code. This is an extremely powerful feature, but it is also very easy to overlook a problem that can arise when doing so. The problem stems from the fact that methods in a category are added to the class as if they were part of the class itself. This happens at runtime when the category is loaded. The runtime goes through each method implemented by a category and adds it to the class’s method list. If a method in a category already exists, the category method wins and becomes the implementation of that method. This overriding can happen over and over again in fact, so a method in one category can override a method in another category that overrides a method in the main class implementation. The last category to be loaded wins.

For example, suppose that you decide to add a category on NSString to provide some helper methods for dealing with strings related to HTTP URLs. You may decide to define the category like this:

@interface NSString (HTTP)

// Encode a string with URL encoding
- (NSString*)urlEncodedString;

// Decode a URL encoded string
- (NSString*)urlDecodedString;

@end

This reads absolutely fine here, but consider what might happen if another category is added that also adds methods to NSString. The second category might also add a method called urlEncodedString but might implement it slightly differently and incorrectly for your purposes. If loaded after your category, the second category will win, and your code will be calling the implementation defined in that category. This may cause your own code to not work properly, as it will get unexpected results. This bug may be hard to track down, as you may not know that your implementation of urlEncodedString is not the code being run.

A typical way to overcome this problem is to namespace the category name and the methods it defines.The only way within Objective-C to namespace is to prepend names with a common prefix. Just as you should do with classes (see Item 15), you should choose a prefix that suits the situation. Often, the prefix will be the same one used with the rest of your application or library. Thus, the NSStringcategory might become the following for a prefix of ABC:

@interface NSString (ABC_HTTP)

// Encode a string with URL encoding
- (NSString*)abc_urlEncodedString;

// Decode a URL encoded string
- (NSString*)abc_urlDecodedString;

@end

Technically, you don’t have to namespace the name of the category itself. Nothing goes wrong if you have two categories named the same. But it’s not good practice, and you will get a compiler warning that looks like this:

warning: duplicate definition of category 'HTTP' on interface
'NSString'

It is not impossible for another category to override your method, but it’s now much less likely, since another library is unlikely to use the same prefix. It also avoids the potential for the developer of the class to add in an update a method that clashes with your added method. For instance, if Apple were to add the method urlEncodedString to NSString, your method of the same name would override Apple’s, which is undesirable, since other users of NSString may be expecting the output from Apple’s implementation. Or Apple’s implementation may include side effects that your method does not provide and potentially produce inconsistencies internally, producing bugs that are hard to find.

You also need to remember that methods added to a class in a category are available to every single instance of that class within your application. If you add methods to a system-supplied class, such asNSStringNSArray or NSNumber, for example, every instance of those classes will be able to call your added methods even if they are not created from your own code. If you accidentally override a method by using the category or clash with a category added by a third-party library, strange bugs can occur because you think it’s your code being executed when it’s not. Similarly, purposefully overriding methods in a category is bad practice, especially if your code will form a library used by other developers who might rely on the existing functionality, for instance. Worse still, another developer may override the same method, in which case the method winning in the overriding process is undefined. This is another example of why you should namespace method names in categories.

Things to Remember

Image Always prepend your naming prefix to the names of categories you add to classes that are not your own.

Image Always prepend your naming prefix to the method names within categories you add to classes that are not your own.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值