Dee*_*pak 1 iphone cocoa cocoa-touch
我有一个非常明确的问题:
//.h file
@property (nonatomic, retain)NSMutableString * retainString;
@property (nonatomic, copy)NSMutableString * copyString;
//.m file
@synthesis retainString, copyString;
-(void)Process
{
NSMutableString *test = [[NSMutableString alloc]inti];//retain count should be 1
self.retainString = test;
self.copyString = test;
}
Run Code Online (Sandbox Code Playgroud)
条件.1-> //保留两者的计数应该是2.因为它们指向具有保留计数2的相同内存位置,所以应该如何写入释放.
条件.2-> // //保留测试计数为1,copyString为2.由于两者都保持不同的内存位置.但我们可以写[copyString release].
这个设置实际上做了一些非常有趣的事情,并提出了一些关于Objective-C内存管理的好点.我们先重申一下代码:
// Testing.h
@interface Testing : NSObject {
NSMutableString *retainString;
NSMutableString *copyString;
}
@property(nonatomic,retain) NSMutableString *retainString;
@property(nonatomic,copy) NSMutableString *copyString;
Run Code Online (Sandbox Code Playgroud)
// Testing.m
@implementation Testing
@synthesize retainString, copyString;
- (id)init {
if(self = [super init]) {
NSMutableString *test = [[NSMutableString alloc] init];
NSLog(@"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
self.retainString = test;
NSLog(@"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
self.copyString = test;
NSLog(@"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
[self.copyString appendFormat:@"test"];
NSLog(@"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
}
return self;
}
@endRun Code Online (Sandbox Code Playgroud)
这会产生日志输出:
2009-12-24 03:35:01.408 RetainCountTesting[1429:40b] test 1; retain 0; copy 0 2009-12-24 03:35:01.410 RetainCountTesting[1429:40b] test 2; retain 2; copy 0 2009-12-24 03:35:01.410 RetainCountTesting[1429:40b] test 2; retain 2; copy 2147483647 2009-12-24 03:35:01.413 RetainCountTesting[1429:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendFormat:'
那么这里发生了什么?前两个调用相当简单:
alloc/ init创建一个新的NSMutableString对象,其保留计数为1.我们有一个对象,其中一个保留.retained属性的赋值会按预期增加保留计数.我们有一个对象有两个保留.这是奇怪的地方.对copy财产的转让确实可以复制,但不是按照你期望的方式.NSString和NSMutableString是所谓的类集群的一部分 - 当您创建或修改字符串时,它可能是也可能不是您期望的类的实例.语言可能会将其变为幕后的其他表示.
在这种特殊情况下,当执行复制时,显然语言决定字符串(因为它不包含任何信息)被认为是不可变的,并且这样做.当人们做类似的事情时经常会看到这种情况[[NSString alloc] initWithString:@"hello"]- 它是一个常量的静态字符串,因此不需要动态分配对象.保持静态有助于运行时更好地运行.
所以现在我们有两个对象:test保留两次的原始对象,以及静态的新对象,因此保留计数为INT_MAX.最后,由于新字符串是不可变的,因此在其上调用mutator方法会导致程序死亡.
顺便说一句,从改变原有的呼叫init,以initWithString:确实让副本任务执行(有点)如预期-你只得到了复制的对象上保留1个计数,但你仍然可以发生变异它.同样,这可能是由于编译器内部的一些优化魔法决定了字符串是静态的,并且没有理由让它变得可变,如果它没有.
回答你的最后一个问题:是的,你可以调用release这些对象中的任何一个.它不会做太多.充其量,你将销毁复制的对象(因为它的保留计数为1); 在最坏的情况下,它对静态字符串对象没有任何作用.但是,我建议继续处理属性:而不是释放复制的对象,为什么不这样做self.copyString = nil;呢?由于它调用属性setter,它会根据需要处理释放,然后你没有指向仍然漂浮的对象的指针.
有关所有这些的更多信息,请考虑阅读: