Ios 何时释放对象,使用ARC将强引用指定给弱引用?

Ios 何时释放对象,使用ARC将强引用指定给弱引用?,ios,objective-c,properties,automatic-ref-counting,Ios,Objective C,Properties,Automatic Ref Counting,例如,如果我们有两个具有NSString属性的对象,一个是弱对象,另一个是强对象,如下所示 @interface Class1 : NSObject @property (weak) NSString *weakString; @end @interface Class2 : NSObject @property (strong) NSString *strongString; @end 然后这样做: NSString *string = [[NSString alloc] initWit

例如,如果我们有两个具有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将第一个版本发送给字符串,将strongString分配给weakString不会更改保留计数,然后将nil分配给strongString将第二个版本发送给字符串,甚至将nil分配给c2,所以释放c2应该将第二次释放发送到字符串,所以现在weakString(和so字符串)的重新计数应该为零,然后释放,所以如果我们试图访问它,weakString归零为零


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

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);

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

取消分配不会立即发生

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

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

输出:str=(空)

现在,如果您将weakString属性更改为“强”而不是“弱”

@property (strong) NSString *weakString;
输出:str=bla

  • 您计算的保留计数是正确的

  • ARC只是在编译时为您添加保留/释放代码,所以基本规则与手动管理内存相同。当retain count为零时,将立即解除分配

  • 上面的示例是一个特例:NSString处于为性能而管理的特殊内存之下。字符串内容是不可变的。相同的字符串内容将指向相同的内存地址,以避免多次重复。NSString retain计数太大,无法释放


  • 只要您至少有一个强引用,就不应该将对象解除分配/设置为
    nil
    。我知道,但在将nil分配给strongString和string之后,强引用不应该再存在,或者我错了?哦,如果您担心的话:解除分配不会立即发生。它可能会稍微延迟。解除分配发生在下一个运行循环周期,但问题是根本没有发生,但如果跳过强分配,则会发生解除分配immediatelly@Rob我这样做了,行为没有改变谢谢,我做了测试,它按预期工作,因此,似乎分配给属性strong的对象(即使该属性已设置为nil)在自动释放池未耗尽之前不会释放。但是当当前的自动释放池实际耗尽时?@Manu我根本不清楚
    weak
    NSString
    属性是
    nil
    -ed。我修改了上面的示例,使视图控制器的
    c1
    c2
    类属性,很久以后,当我检查
    c1
    weak
    属性时,
    weakString
    仍然报告一个值,即使应用程序早已删除了对它的任何强引用。总之,我不会依赖对
    NSString
    weak
    引用来报告
    nil
    ,即使你的应用程序不再有任何
    strong
    引用。当对象被释放时,weak变量被设置为nil。在NSString情况下,字符串对象可能不会被释放,因为它是一个不朽常量字符串。在其他情况下,对象可能尚未解除分配,因为它已自动释放,并且自动释放池尚未耗尽。
    @property (strong) NSString *weakString;