我一直在努力了解iOS中强引用和弱引用之间的区别。我的理解是:
//.h File
@property(nonatomic,strong) NSString* myStrongString;
@property(nonatomic,weak) NSString* myWeakString;
//.m File
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)assignTempString{
self.myStrongString = [[NSString alloc] initWithString:@"Varun Mehta"];
}
- (IBAction)printAssignedString:(id)sender {
NSLog(@"Object will have strong reference so it will print my name==%@",self.myStrongString);
}
根据我的理解,当我通过使用myWeakString重复上述步骤时,它应该打印null。但它还在打印我的名字。任何人都知道为什么会这样。
但是当我用[[NSString alloc] initWithString:@"Varun Mehta"]
或[NSString stringWithFormat:@"Varun Mehta"]
替换[[NSString alloc] initWithFormat:@"Varun Mehta"]
后,结果就像我预期的那样。
答案 0 :(得分:2)
这里有几点需要考虑。
静态声明的字符串内置在您的应用中,因此它不会被保留或释放,因此对@"my string"
的弱引用始终有效。编译器只是将[[NSString alloc] initWithString:@"Varun Mehta"]
识别为静态字符串并删除了alloc / init。但是,根据定义,处理格式化的任何事情都是创建一个新字符串,因此新字符串服从弱引用规则并立即取消分配,使引用无效。
如果您访问一个最终存在于自动释放池中的弱保留对象,它实际上将被解除分配,直到您的所有方法都返回并且运行循环返回另一个循环(从而耗尽自动释放池) ),所以你可以继续使用该对象,即使它已经死了#34;这通常仅在与非ARC代码交互时才会发生。
答案 1 :(得分:1)
如果您需要练习,请尝试以下代码:
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
}
-(void)assignTempString{
@autoreleasepool
{
self.myStrongString = [NSString stringWithFormat:@"%@", @"Strong string"];
self.myWeakString = [NSString stringWithFormat:@"%@", @"Weak string"];
}
}
- (IBAction)printAssignedString:(id)sender {
NSLog(@"Strong ptr content: %@",self.myStrongString);
NSLog(@"Weak ptr content: %@",self.myWeakString);
}
答案 2 :(得分:0)
[NSString alloc] 将分配一个ARC管理的对象,并将其保留计数设置为1.只要您的视图控制器处于活动状态,此保留计数将为1,因此它不会被解除分配。 [NSString stringWithFormat:] 返回一个自动释放的字符串,该字符串在执行 [self assignTempString] 后被解除分配。
答案 3 :(得分:0)
两种方法initWithString
和stringWithFormat
确切地说明了预期的内容。
因此initWithString
期望您创建分配内存然后初始化它。
虽然stringWithFormat
希望您只指向字符串。
使用强弱变量执行init
时,它将一直存在到程序结束。
当你指出的时候;
strong literal将保留引用,因此不允许ARC清理字符串文字,
weak literal不会保留引用,因此ARC可以在函数调用后立即自动清理它。
希望它澄清为你工作。
答案 4 :(得分:0)
您遇到的问题是因为NSString的实现方式。
由于NSString对象是不可变的,因此当您使用带有字符串文字的stringWithString:
作为参数时,编译器会使用快捷方式。如果此参数和其他相关方法的参数是字符串文字,则返回的值将仅指向字符串文字。整个对象实例化被优化掉了。
字符串文字不会被释放。但是,在dealloc期间,弱变量只是nil'd,所以如果从不调用dealloc,则弱变量永远不会设置为nil。
如果您使用stringWithFormat:
,则不会发生这种情况。即使只使用字符串文字作为参数也会创建新的字符串实例
为什么?最有可能的原因是Apple决定检查stringWithFormat:
是否与没有任何格式说明符的字符串文字一起使用是不值得的。
这是一个实施细节,不要想太久这个决定。它不应该影响你编写的代码。我建议你将每个非文字字符串(即没有任何NSString方法的@“Foo”)视为动态创建的NSString(即使用isEqualToString:
进行所有字符串比较)
此日志记录代码将显示此重用行为。它将显示所有NSString实例的相同地址,因为编译器已将所有这些调用优化为简单@"Foo"
。
NSLog(@"%p", @"Foo");
NSLog(@"%p", [[NSString alloc] initWithString:@"Foo"]);
NSLog(@"%p", [NSString stringWithString:@"Foo"]);
NSLog(@"%p", [[NSString stringWithString:@"Foo"] copy]);
NSLog(@"%p", [@"Foo" copy]);
在较新版本的Xcode中,您甚至会收到有关此代码的警告:
使用initWithString:文字是多余的 使用stringWithString:文字是多余的