Objective-C ARC 强引用和弱引用 "object will be released after assignment" 警告 - 但未发布
Objective-C ARC Strong and Weak references "object will be released after assignment" warning - but it doesn't get released
我正在做这个简单的 Objective-C 练习以更好地理解 ARC,这是一个程序,当引用设置为 Strong 时应该显示 R2D2,当引用设置为 Weak 时会失败。但是,代码仍然可以编译,即使有警告说对象将被释放。
main.m
#import <Foundation/Foundation.h>
#import "Robot.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",robot.firstString,robot.secondString);
}
return 0;
}
Robot.m
#import "Robot.h"
@implementation Robot
@end
Robot.h
#import <Foundation/Foundation.h>
@interface Robot : NSObject
@property (strong) NSString *firstString;
@property (weak) NSString *secondString;
@end
谢谢
编译器很聪明。编译器可以替换
[[NSString alloc]initWithFormat:@"D%d",2]
和
@"D2"
这是一个 NSString 常量,永远不会被释放。另一种可能性:优化编译器替换
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",robot.firstString,robot.secondString);
和
Robot *robot = [[Robot alloc]init];
NSString* tmp1 =[[NSString alloc]initWithFormat:@"R%d",2];
NSString* tmp2 = [[NSString alloc]initWithFormat:@"D%d",2];
robot.firstString = tmp1;
robot.secondString = tmp2;
NSLog(@"%@%@",tmp1,tmp2);
然后
NSString* tmp1 =[[NSString alloc]initWithFormat:@"R%d",2];
NSString* tmp2 = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",tmp1,tmp2);
然后
NSString* tmp1 =@"R2";
NSString* tmp2 = @"D2";
NSLog(@"%@%@",tmp1,tmp2);
然后
NSLog(@"R2D2");
哦,这很有趣。您 运行 变成了标记指针。
@interface Robot : NSObject
@property (strong) NSString *firstString;
@property (weak) NSString *secondString;
@end
@implementation Robot
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@ %@",robot.firstString,robot.secondString);
NSLog(@"%p %p",robot.firstString,robot.secondString);
robot.secondString = [[NSString alloc]initWithFormat:@"argy bargy foo foo %d",2];
NSLog(@"%@ %@",robot.firstString,robot.secondString);
NSLog(@"%p %p",robot.firstString,robot.secondString);
}
return 0;
}
输出:
R2 D2
0x325225 0x324425
R2 (null)
0x325225 0x0
请注意,您的弱字符串有一个 奇地址 。但是分配不能落在奇数地址上!事实上,堆上的分配 通常 按 16 字节对齐(尽管静态分配的特殊情况字符串可能只是偶数地址)。
那个奇数地址表示bit 0
中有一个1
。这表示正在使用 标记指针 。也就是说,字符串在对象的地址中编码,运行时检测到低位已设置,因此在特殊情况下它指向标记指针。
其实如果在ASCIItable中查找0x32
和0x44
,前者是字符2
,后者是字符D
。 0x25
是字符串(2)的长度和class索引(+低位)。
因此,您永远不会看到弱引用变为零,因为没有涉及分配。没有分配,就永远不会有释放,因此,字符串引用永远不会无效。
第二个字符串-- @"argy bargy foo foo 2
-- 不适合标记指针,因此是堆分配。
我正在做这个简单的 Objective-C 练习以更好地理解 ARC,这是一个程序,当引用设置为 Strong 时应该显示 R2D2,当引用设置为 Weak 时会失败。但是,代码仍然可以编译,即使有警告说对象将被释放。
main.m
#import <Foundation/Foundation.h>
#import "Robot.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",robot.firstString,robot.secondString);
}
return 0;
}
Robot.m
#import "Robot.h"
@implementation Robot
@end
Robot.h
#import <Foundation/Foundation.h>
@interface Robot : NSObject
@property (strong) NSString *firstString;
@property (weak) NSString *secondString;
@end
谢谢
编译器很聪明。编译器可以替换
[[NSString alloc]initWithFormat:@"D%d",2]
和
@"D2"
这是一个 NSString 常量,永远不会被释放。另一种可能性:优化编译器替换
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",robot.firstString,robot.secondString);
和
Robot *robot = [[Robot alloc]init];
NSString* tmp1 =[[NSString alloc]initWithFormat:@"R%d",2];
NSString* tmp2 = [[NSString alloc]initWithFormat:@"D%d",2];
robot.firstString = tmp1;
robot.secondString = tmp2;
NSLog(@"%@%@",tmp1,tmp2);
然后
NSString* tmp1 =[[NSString alloc]initWithFormat:@"R%d",2];
NSString* tmp2 = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@%@",tmp1,tmp2);
然后
NSString* tmp1 =@"R2";
NSString* tmp2 = @"D2";
NSLog(@"%@%@",tmp1,tmp2);
然后
NSLog(@"R2D2");
哦,这很有趣。您 运行 变成了标记指针。
@interface Robot : NSObject
@property (strong) NSString *firstString;
@property (weak) NSString *secondString;
@end
@implementation Robot
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
Robot *robot = [[Robot alloc]init];
robot.firstString =[[NSString alloc]initWithFormat:@"R%d",2];
robot.secondString = [[NSString alloc]initWithFormat:@"D%d",2];
NSLog(@"%@ %@",robot.firstString,robot.secondString);
NSLog(@"%p %p",robot.firstString,robot.secondString);
robot.secondString = [[NSString alloc]initWithFormat:@"argy bargy foo foo %d",2];
NSLog(@"%@ %@",robot.firstString,robot.secondString);
NSLog(@"%p %p",robot.firstString,robot.secondString);
}
return 0;
}
输出:
R2 D2
0x325225 0x324425
R2 (null)
0x325225 0x0
请注意,您的弱字符串有一个 奇地址 。但是分配不能落在奇数地址上!事实上,堆上的分配 通常 按 16 字节对齐(尽管静态分配的特殊情况字符串可能只是偶数地址)。
那个奇数地址表示bit 0
中有一个1
。这表示正在使用 标记指针 。也就是说,字符串在对象的地址中编码,运行时检测到低位已设置,因此在特殊情况下它指向标记指针。
其实如果在ASCIItable中查找0x32
和0x44
,前者是字符2
,后者是字符D
。 0x25
是字符串(2)的长度和class索引(+低位)。
因此,您永远不会看到弱引用变为零,因为没有涉及分配。没有分配,就永远不会有释放,因此,字符串引用永远不会无效。
第二个字符串-- @"argy bargy foo foo 2
-- 不适合标记指针,因此是堆分配。