目标c-强参考文献和弱参考文献之间的差异(使用ARC)请不要理论.我从理论上知道区别



我一直在努力理解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 stringWithFormat:@"Varun Mehta"][[NSString alloc] initWithFormat:@"Varun Mehta"]替换[[NSString alloc] initWithString:@"Varun Mehta"]时,结果正如我所期望的那样。

这里有几件事需要考虑。

  1. 一个静态声明的字符串被构建到你的应用程序中,所以它不会被真正保留或释放,因此对@"my string"的弱引用总是有效的。编译器只是将[[NSString alloc] initWithString:@"Varun Mehta"]识别为一个静态字符串,并删除您的alloc/init。然而,根据定义,任何处理格式化的东西都是创建一个新字符串,因此新字符串遵守弱引用规则,并立即被释放,从而消除引用。

  2. 如果您访问了一个最终在自动释放池中的弱保留对象,那么在所有方法返回并且运行循环返回到另一个循环(从而耗尽自动释放池)之前,它实际上不会被释放,因此即使对象"死了",您也可以继续处理它。这通常仅在与非ARC代码交互时发生。

如果您需要练习,请尝试以下代码:

- (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);
}

[NString alloc]将分配一个ARC托管对象,并将其保留计数设置为1。只要视图控制器处于活动状态,此保留计数将为1,因此不会解除分配[NSString字符串WithFormat:]返回一个自动释放的字符串,该字符串在执行[sel-assignTempString]后被释放。

两个方法initWithStringstringWithFormat准确地表明了预期结果。所以initWithString希望您创建分配内存,然后初始化它。而stringWithFormat希望您只指向字符串。

当您使用强/弱变量执行init时,它将一直存在到程序结束。当你指向;强文字将保留引用,因此将不允许ARC清除字符串文字,弱文字不会保留引用,因此ARC可以在函数调用后立即清除它。

希望它能澄清对你的工作。

您所经历的一切都是因为NSString的实现方式。

由于NSString对象是不可变的,所以当您使用带有字符串文字作为参数的stringWithString:时,编译器会使用快捷方式。如果this和其他相关方法的参数是字符串文字,则返回的值将仅指向字符串文字。整个对象实例化都被优化掉了。

字符串文字不会被释放。但是弱变量在dealloc期间仅为nil,因此如果从未调用dealloc,则弱变量永远不会设置为nil。

如果使用stringWithFormat:,则不会发生这种情况。即使只使用字符串文字作为参数,也会创建新的字符串实例
为什么?很可能是因为苹果认为不值得检查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:与文字一起使用是多余的
使用字符串WithString:带文字是多余的

最新更新