为什么弱属性和__weak实例变量表现不同

时间:2016-12-22 18:47:29

标签: ios objective-c memory-management properties

我知道强和弱是属性声明中使用的修饰符,而__strong和__weak用于实例变量的声明...强说只要我拥有它就保持对象在内存中而弱则表示保留对象在记忆中,只要别人有强烈的参考...对吧?但我没有得到为什么弱属性和__weak实例变量表现不同?这就是我想知道的......

 @interface DemoViewController (){

    __weak NSArray *weakArray;
    __strong NSArray *strongArray;
    __weak NSString *weakString;
    __strong NSString *strongString;  
 }

@property (weak) NSString *weakStringProperty;
@property (strong) NSString *strongStringProperty;

@property (weak) NSArray *weakArrayProperty;
@property (strong) NSArray *strongArrayProperty;

@end

@implementation DemoViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    strongArray = [[NSArray alloc] initWithObjects:@"one",@"two", nil];
    weakArray = strongArray;

    NSLog(@"Round:1 strongArray is %@.", strongArray);
    NSLog(@"Round:1 weakArray is %@.", weakArray);

    strongArray = nil;

    NSLog(@"Round:2 strongArray is %@.", strongArray);
    NSLog(@"Round:2 weakArray is %@.", weakArray);

    self.strongArrayProperty = [[NSArray alloc] initWithObjects:@"one",@"two", nil];
    self.weakArrayProperty = self.strongArrayProperty;

    NSLog(@"Round:1 strongArrayProperty is %@.", self.strongArrayProperty);
    NSLog(@"Round:1 weakArrayProperty is %@.", self.weakArrayProperty);

    self.strongArrayProperty = nil;

    NSLog(@"Round:2 strongArrayProperty is %@.", self.strongArrayProperty);
    NSLog(@"Round:2 weakArrayProperty is %@.", self.weakArrayProperty);


    strongString = [[NSString alloc]initWithFormat:@"instanceVariable"];
    weakString = strongString;

    NSLog(@"Round:1 strongString is %@.", strongString);
    NSLog(@"Round:1 weakString is %@.", weakString);

    strongString = nil;

    NSLog(@"Round:2 strongString is %@.", strongString);
    NSLog(@"Round:2 weakString is %@.", weakString);

    self.strongStringProperty = [[NSString alloc]initWithFormat:@"Property"];
    self.weakStringProperty = self.strongStringProperty;

    NSLog(@"Round:1 strongStringProperty is %@.", self.strongStringProperty);
    NSLog(@"Round:1 weakStringProperty is %@.", self.weakStringProperty);

    self.strongStringProperty = nil;

    NSLog(@"Round:2 strongStringProperty is %@.", self.strongStringProperty);
    NSLog(@"Round:2 weakStringProperty is %@.", self.weakStringProperty);

}
@end

以下是结果日志

Round:1 strongArray is (
    one,
    two
).
 Round:1 weakArray is (
    one,
    two
).
 Round:2 strongArray is (null).
 Round:2 weakArray is (null).


 Round:1 strongArrayProperty is (
    one,
    two
).
Round:1 weakArrayProperty is (
    one,
    two
).
Round:2 strongArrayProperty is (null).
Round:2 weakArrayProperty is (
    one,
    two
).           —???

Round:1 strongString is instanceVariable.
Round:1 weakString is instanceVariable.
Round:2 strongString is (null).
Round:2 weakString is (null).


Round:1 strongStringProperty is Property.
Round:1 weakStringProperty is Property.
Round:2 strongStringProperty is (null).
Round:2 weakStringProperty is Property.   ——??

两个弱实例变量在它们弱引用的对象之后打印(null),设置为nil并且这是预期的但我想知道为什么弱属性weakStringProperty和weakArrayProperty仍然打印它们之前的值和表现得好像他们分别强烈指向strongStringProperty和strongArrayProperty ??

谢谢:)

2 个答案:

答案 0 :(得分:1)

weakStringProperty不是nil,因为基金会仍在保留它。

当您致电[[NSString alloc]initWithFormat:@"Property"]时,基金会决定将该字符串作为NSTaggedPointerString实习,然后将其保留以供将来使用。您可以通过记录类来验证这一点:

NSLog(@"kindof: %@", [self.weakStringProperty class]);

我不确定系统使用什么标准来决定创建这些字符串,但长度和可变性是因素。以下任一项都可以得到您想要的结果。

// Longer string
self.strongStringProperty = [[NSString alloc]initWithFormat:@"Property la la la"];

// Mutable string
self.strongStringProperty = [[NSMutableString alloc]initWithFormat:@"Property"];

答案 1 :(得分:1)

您的属性是原子的,因为您没有声明它们是非原子的。原子属性返回一个保留并自动释放的对象,因此该对象将保留在自动释放池中并保持保留状态,直到退出viewDidLoad方法。

例如更改为

@property (weak, nonatomic, readwrite) NSString *weakStringProperty; 

您更有可能获得预期的结果。或者稍后用另一种方法检查属性,弱属性可能为零。

但是,iOS经常创建永远不会发布的对象。例如,一个空的NSArray对象永远不会被释放。对于许多NSNumber对象,短字符串,@ YES和@NO等也是如此。当您认为对象将被释放时,无法保证对象将被释放,因此无法保证弱对象变为零。