首页 文章

当释放对象时,使用ARC分配对弱引用的强引用?

提问于
浏览
0

例如,如果我们有2个具有NSString属性的对象,一个是弱的,一个是这样的强

@interface Class1 : NSObject
@property (weak) NSString *weakString;
@end


@interface Class2 : NSObject
@property (strong) NSString *strongString;
@end

然后这样做:

NSString *string = [[NSString alloc] initWithString:@"bla"];

Class2 *c2 = [[Class2 alloc] init];
c2.strongString = string;

string = nil;

Class1 *c1 = [[Class1 alloc] init];
c1.weakString = c2.strongString;

c2.strongString = nil;

甚至

c2 = nil;

然后c1.weakString包含什么?

将字符串赋值给strongString调用一个保留字符串,将字符串赋值给nil将第一个版本发送给字符串,将weakString赋值给weakString不会改变保留计数,然后将nil分配给strongString将第二个版本发送到字符串甚至分配nil到c2,所以释放c2应该将第二个版本发送到字符串,所以现在,weakString的retainCount(以及字符串)应该为零然后释放,因此如果我们尝试访问它,则weakString归零为nil

但'weakString'仍然包含“bla”所以原来的字符串对象,为什么?

3 回答

  • 0

    解除分配不会立即发生 .

    将您的实现放在 @autoreleasepool 然后打印weakString,它将是零 .

    (使用 initWithFormat 进行字符串初始化而不是冗余 initWithString

    Class2 *c2 = nil;
    Class1 *c1 = nil;
    
    @autoreleasepool {
        NSString *string = [[NSString alloc] initWithFormat:@"bla"];
    
        c2 = [[Class2 alloc] init];
        c2.strongString = string;
    
        string = nil;
    
        c1 = [[Class1 alloc] init];
        c1.weakString = c2.strongString;
    
        c2.strongString = nil;
    }
    
    NSLog(@"str = %@", c1.weakString);
    

    输出: str = (null)

    现在,如果将weakString属性更改为“strong”而不是“weak”

    @property (strong) NSString *weakString;
    

    输出: str = bla

  • 0
    • 您计算的保留计数是对的 .

    • ARC只是在编译时为您添加保留/释放代码,因此基本规则与手动管理内存相同 . 当retain count为零时,它将立即被释放 .

    • 上面的例子是一个特例:NSString在为性能管理的特殊内存下 . 字符串内容是不可变的 . 相同的字符串内容将指向相同的内存地址,不会重复多次 . NSString保留计数太大而无法释放 .

  • 2

    NSString 是一个类集群,并在后台进行一些不直观的优化 . 如果您使用某些自定义 NSObject 子类而不是 NSString 重复测试,它将表现得更像您期望的那样 .

    想象一下您的示例的以下变化:

    @interface MyTestObject : NSObject
    @end
    
    @interface Class1 : NSObject
    @property (weak) NSString *weakString;
    @property (weak) MyTestObject *weakObject;
    @end
    
    @interface Class2 : NSObject
    @property (strong) NSString *strongString;
    @property (strong) MyTestObject *strongObject;
    @end
    

    然后考虑:

    Class2 *c2 = [[Class2 alloc] init];
    Class1 *c1 = [[Class1 alloc] init];
    
    @autoreleasepool {
        NSString *string = [[NSString alloc] initWithString:@"bla"];
        MyTestObject *object = [[MyTestObject alloc] init];
    
        c2.strongString = string;
        c2.strongObject = object;
    
        string = nil;
        object = nil;
    
        c1.weakString = c2.strongString;
        c1.weakObject = c2.strongObject;
    
        c2.strongString = nil;
        c2.strongObject = nil;
    }
    
    NSLog(@"c1.weakString = %@", c1.weakString);
    NSLog(@"c1.weakObject = %@", c1.weakObject);
    

    你希望 weakStringweakObject 都是 nil ,但只有 weakObject . 这是 NSString 类中正在进行的一些内部实现优化的结果 .

相关问题