弱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_unretained
variables的不同行为。
- (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);