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中查找0x320x44,前者是字符2,后者是字符D0x25是字符串(2)的长度和class索引(+低位)。

因此,您永远不会看到弱引用变为零,因为没有涉及分配。没有分配,就永远不会有释放,因此,字符串引用永远不会无效。

第二个字符串-- @"argy bargy foo foo 2-- 不适合标记指针,因此是堆分配。