强参考和弱参考之间的差异(使用ARC)请不要理论......我从理论上知道差异

时间:2014-04-11 08:10:08

标签: objective-c xcode ios7

我一直在努力了解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"]后,结果就像我预期的那样。

5 个答案:

答案 0 :(得分:2)

这里有几点需要考虑。

  1. 静态声明的字符串内置在您的应用中,因此它不会被保留或释放,因此对@"my string"的弱引用始终有效。编译器只是将[[NSString alloc] initWithString:@"Varun Mehta"]识别为静态字符串并删除了alloc / init。但是,根据定义,处理格式化的任何事情都是创建一个新字符串,因此新字符串服从弱引用规则并立即取消分配,使引用无效。

  2. 如果您访问一个最终存在于自动释放池中的弱保留对象,它实际上将被解除分配,直到您的所有方法都返回并且运行循环返回另一个循环(从而耗尽自动释放池) ),所以你可以继续使用该对象,即使它已经死了#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)

两种方法initWithStringstringWithFormat确切地说明了预期的内容。 因此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:文字是多余的