NSMutableString和NSString的类别导致绑定混乱? [英] Categories for NSMutableString and NSString causing binding confusion?
问题描述
我已经扩展了NSString和NSMutableString与一些方便的方法使用类别。这些添加的方法具有相同的名称,但具有不同的实现。例如,我已经实现rubystrip函数,删除端点的空格字符,但对于NSString它返回一个新的字符串,对于NSMutableString它使用deleteCharactersInRange剥离现有的字符串并返回它(像红宝石条!)。
I have extended both NSString and NSMutableString with some convenience methods using categories. These added methods have the same name, but have different implementations. For e.g., I have implemented the ruby "strip" function that removes space characters at the endpoints for both but for NSString it returns a new string, and for NSMutableString it uses the "deleteCharactersInRange" to strip the existing string and return it (like the ruby strip!).
以下是典型的标题:
@interface NSString (Extensions)
-(NSString *)strip;
@end
和
@interface NSMutableString (Extensions)
-(void)strip;
@end
$ b < ],它试图运行NSMutableString版本并引发一个扩展。
The problem is that when I declare NSString *s and run [s strip], it tries to run the NSMutableString version and raises an extension.
NSString *s = @" This is a simple string ";
NSLog([s strip]);
失败:
由于未捕获而终止应用程序
exception
'NSInvalidArgumentException',reason:
'尝试使用deleteCharactersInRange:'
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with deleteCharactersInRange:'
推荐答案
你被一个实现细节咬了:一些NSString对象是NSMutableString的子类的实例,
You've been bitten by an implementation detail: Some NSString objects are instances of a subclass of NSMutableString, with only a private flag controlling whether the object is mutable or not.
这是一个测试应用程式:
Here's a test app:
#import <Foundation/Foundation.h>
int main(int argc, char **argv) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *str = [NSString stringWithUTF8String:"Test string"];
NSLog(@"%@ is a kind of NSMutableString? %@", [str class], [str isKindOfClass:[NSMutableString class]] ? @"YES" : @"NO");
[pool drain];
return EXIT_SUCCESS;
}
如果你至少编译并运行Leopard得到这个输出:
If you compile and run this on Leopard (at least), you'll get this output:
NSCFString is a kind of NSMutableString? YES
正如我所说,对象有一个私人标志控制是否可变。因为我经历了NSString而不是NSMutableString,这个对象是不可变的。如果你尝试改变它,像这样:
As I said, the object has a private flag controlling whether it's mutable or not. Since I went through NSString and not NSMutableString, this object is not mutable. If you try to mutate it, like this:
NSMutableString *mstr = str;
[mstr appendString:@" is mutable!"];
你会得到一个当之无愧的警告但这是一个坏主意)和(2)在你自己的应用程序中有相同的异常。
you'll get (1) a well-deserved warning (which one could silence with a cast, but that would be a bad idea) and (2) the same exception you got in your own application.
我建议的解决方案是将你的变形条包裹在 @try
阻止,并在 return [super strip]
) > @catch 阻止。
The solution I suggest is to wrap your mutating strip in a @try
block, and call up to your NSString implementation (return [super strip]
) in the @catch
block.
此外,我不建议给方法不同的返回类型。我将使变化的一个返回 self
,如 retain
和 autorelease
do。然后,你总是可以这样做:
Also, I wouldn't recommend giving the method different return types. I would make the mutating one return self
, like retain
and autorelease
do. Then, you can always do this:
NSString *unstripped = …;
NSString *stripped = [unstripped strip];
而不必担心 untripted
是否是可变字符串或不。实际上,此示例提供了一个很好的例子,您应该完全删除变异的 strip
,或者将复制 strip
重命名为 stringByStripping
或某事(类似于 replaceOccurrencesOfString:...
和 stringByReplacingOccurrencesOfString:...
)。
without worrying about whether unstripped
is a mutable string or not. In fact, this example makes a good case that you should remove the mutating strip
entirely, or rename the copying strip
to stringByStripping
or something (by analogy with replaceOccurrencesOfString:…
and stringByReplacingOccurrencesOfString:…
).
这篇关于NSMutableString和NSString的类别导致绑定混乱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!