弱NSStringvariables不是零后设置唯一强引用为零

我有这个代码的问题:

__strong NSString *yourString = @"Your String"; __weak NSString *myString = yourString; yourString = nil; __unsafe_unretained NSString *theirString = myString; NSLog(@"%p %@", yourString, yourString); NSLog(@"%p %@", myString, myString); NSLog(@"%p %@", theirString, theirString); 

我期待所有的指针在这个时候是nil ,但他们不是,我不明白为什么。 第一个(强)指针是nil但其他两个不是。 这是为什么?

TL; 博士:问题是string文字永远不会被释放,所以你的弱指针仍然指向它。


理论

强大的variables将保留它们指向的值。

variables不会保留它们的值,当值被释放时,它们将把它们的指针设置为零(为了安全起见)。

不安全的不存在的值(如你可能可以读取的名称)将不会保留该值,如果它被释放,他们什么都不做,可能指向一个坏的内存


文字和常量

当你使用@"literal string"创build一个string时,它将变成一个永远不会改变的string。 如果您在应用程序的许多地方使用相同的string,则它始终是同一个对象。 string文字不会消失。 使用[[NSString alloc] initWithString:@"literal string"]不会有所作为。 因为它变成了一个指向string的指针。 不过值得注意的是[[NSString alloc] initWithFormat:@"literal string"]; 工作方式不同,将释放其string对象。

逐行:

 __strong NSString *yourString = @"Your String"; 

您正在创build一个指向string的强指针。 这将确保价值不会消失。 在你的情况下,它有点特别,因为string是一个string,在技术上不会被释放

 __weak NSString *myString = yourString; 

你创build一个弱指针来指向与强指针相同的东西。 如果此时强指针指向其他的东西,它指向的值将被释放,然后弱指针将改变它的值,使其指向nil 。 现在它仍然指向强指针一样。

 yourString = nil; 

你强有力的指针指向nil 。 没有指向旧string,所以它应该被释放,如果它不是因为是一个文字string的事实 。 如果您尝试了与您自己创build的其他对象完全相同的内容,则弱variables将会更改,以便指向nil 。 但是,由于string文字是文字,并不会消失。 弱variables仍然指向它。

 __unsafe_unretained NSString *theirString = myString; 

创build一个新的未保留指针,指向指向string文字的弱指针。

 NSLog(@"%p %@", yourString, yourString); NSLog(@"%p %@", myString, myString); NSLog(@"%p %@", theirString, theirString); 

你打印所有的string,并弄糊涂为什么第一个值是nil但其他两个不是。


相关阅读:

string常量和string常量之间有什么区别?

大卫在他的回答中是100%正确的。 我刚刚使用GHUnit添加了四个明确的例子。

对象引用的生存期限定符行为。

使用NSObject作为所有对象的代理,生命周期限定符的行为是预期的。

 - (void) test_usingNSObjects { NSObject *value1 = [[NSObject alloc] init]; NSObject *value2 = [[NSObject alloc] init]; NSObject *value3 = [[NSObject alloc] init]; __strong NSObject *sRefToValue = value1; __weak NSObject *wRefToValue = value2; __unsafe_unretained NSObject *uRefToValue = value3; value1 = value2 = value3 = nil; GHAssertNotNil(sRefToValue, @"Strong reference to the object that was originally \ assigned to value1. Even though value1 was set to nil, the \ strong reference to the object keeps the object from being \ destroyed."); GHAssertNil(wRefToValue, @"Weak reference to the object that was originally assigned to \ value2. When value2 was set to nil, the weak reference does \ not prevent the object from being destroyed. The weak \ reference is also set to nil."); // Removing the #ifdef and #endif lines will result in a EXC_BAD_ACCESS // signal. Receiving a EXC_BAD_ACCESS signal is the expected behavior for // that code. #ifdef RECIEVE_EXC_BAD_ACCESS GHAssertNotNil(uRefToValue, @"Unsafe unretained reference to the object that was \ originally assigned to value3. When value3 was set to nil, \ the unsafe unretained reference does not prevent the object \ from being destroyed. The unsafe unretained reference is \ unaltered and the reference is invalid. Accessing the \ reference will result in EXC_BAD_ACCESS signal."); #endif // To avoid future EXC_BAD_ACCESS signals. uRefToValue = nil; } 

字面NSString s(@“something”)的生存期限定符行为。

这与test_usingNSObjects基本相同,但不是使用NSObject ,而是使用分配了文字string的NSString 。 由于文字string不像其他对象那样被破坏,因此可以观察到__weak__unsafe_unretainedvariables的不同行为。

 - (void) test_usingLiteralNSStrings { NSString *value1 = @"string 1"; NSString *value2 = @"string 2"; NSString *value3 = @"string 3"; __strong NSString *sRefToValue = value1; __weak NSString *wRefToValue = value2; __unsafe_unretained NSString *uRefToValue = value3; value1 = value2 = value3 = nil; GHAssertNotNil(sRefToValue, @"Strong reference to the object that was originally \ assigned to value1. Even though value1 was set to nil, \ literal strings are not destroyed."); GHAssertNotNil(wRefToValue, @"Weak reference to the object that was originally assigned \ to value2. Even though value2 was set to nil, \ literal strings are not destroyed so the weak reference is \ still valid."); GHAssertNotNil(uRefToValue, @"Unsafe unretained reference to the object that was \ originally assigned to value3. Even though value3 was set \ to nil, literal strings are not destroyed so the unsafe \ unretained reference is still valid."); } 

nonliteral NSString的生命周期限定符行为。

这与test_usingNSObjects基本相同,但不是使用NSObject ,而是使用分配了非字串的NSString 。 由于nonliteralstring像其他对象一样被销毁,行为与test_usingNSObjects的行为相同。

 - (void) test_usingNonliteralNSStrings { NSString *value1 = [[NSString alloc] initWithFormat:@"string 1"]; NSString *value2 = [[NSString alloc] initWithFormat:@"string 2"]; NSString *value3 = [[NSString alloc] initWithFormat:@"string 3"]; __strong NSString *sRefToValue = value1; __weak NSString *wRefToValue = value2; __unsafe_unretained NSString *uRefToValue = value3; value1 = value2 = value3 = nil; GHAssertNotNil(sRefToValue, @"Strong reference to the object that was originally \ assigned to value1. Even though value1 was set to nil, the \ strong reference to the object keeps the object from being \ destroyed."); GHAssertNil(wRefToValue, @"Weak reference to the object that was originally assigned to \ value2. When value2 was set to nil, the weak reference does \ not prevent the object from being destroyed. The weak \ reference is also set to nil."); // Removing the #ifdef and #endif lines will result in a EXC_BAD_ACCESS // signal. Receiving a EXC_BAD_ACCESS signal is the expected behavior for // that code. #ifdef RECIEVE_EXC_BAD_ACCESS GHAssertNotNil(uRefToValue, @"Unsafe unretained reference to the object that was \ originally assigned to value3. When value3 was set to nil, \ the unsafe unretained reference does not prevent the object \ from being destroyed. The unsafe unretained reference is \ unaltered and the reference is invalid. Accessing the \ reference will result in EXC_BAD_ACCESS signal."); #endif // To avoid future EXC_BAD_ACCESS signals. uRefToValue = nil; } 

NSString创build – 字面与nonliteral。

显示以各种方式创build的string,如果它们是文字或非文字的。

 - (void) test_stringCreation { NSString *literalString = @"literalString"; NSString *referenced = literalString; NSString *copy = [literalString copy]; NSString *initWithString = [[NSString alloc] initWithString:literalString]; NSString *initWithFormat = [[NSString alloc] initWithFormat:@"%@", literalString]; // Testing that the memory addresses of referenced objects are the same. GHAssertEquals(literalString, @"literalString", @"literal"); GHAssertEquals(referenced, @"literalString", @"literal"); GHAssertEquals(copy, @"literalString", @"literal"); GHAssertEquals(initWithString, @"literalString", @"literal"); GHAssertNotEquals(initWithFormat, @"literalString", @"nonliteral - referenced objects' memory addresses are \ different."); // Testing that the objects referenced are equal, ie isEqual: . GHAssertEqualObjects(literalString, @"literalString", nil); GHAssertEqualObjects(referenced, @"literalString", nil); GHAssertEqualObjects(copy, @"literalString", nil); GHAssertEqualObjects(initWithString, @"literalString", nil); GHAssertEqualObjects(initWithFormat, @"literalString", nil); // Testing that the strings referenced are the same, ie isEqualToString: . GHAssertEqualStrings(literalString, @"literalString", nil); GHAssertEqualStrings(referenced, @"literalString", nil); GHAssertEqualStrings(copy, @"literalString", nil); GHAssertEqualStrings(initWithString, @"literalString", nil); GHAssertEqualStrings(initWithFormat, @"literalString", nil); } 

在自动释放池被排空之后,弱财产将只设置为零。

尝试:

 @autoreleasepool { _strong NSString *yourString = @"Your String"; __weak NSString *myString = yourString; yourString = nil; __unsafe_unretained NSString *theirString = myString; } NSLog(@"%p %@", yourString, yourString); NSLog(@"%p %@", myString, myString); NSLog(@"%p %@", theirString, theirString);