【问题标题】:why weak for property and __weak for instance variable behave differentenly为什么weak for property和__weak for instance变量的行为不同
【发布时间】:2017-05-08 11:24:18
【问题描述】:

我知道 strong 和 weak 是在属性声明中使用的修饰符,而 __strong 和 __weak 在实例变量的声明中使用...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.   ——??

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

谢谢:)

【问题讨论】:

  • 我能够在第 2 轮中将 strongArrayProperty 和 weakArrayProperty 作为(null)。虽然,第 2 轮中的 weakStringProperty 仍然是“属性”。这很奇怪,因为 ARC 应该在技术上处理这个问题。 PS-我在我的电脑上运行了这个。
  • 我认为原因是因为 main 方法有一个封闭应用程序运行的自动释放池,所以保留了弱属性。由于自动释放池,weak 属性不会立即设置为 nil。虽然,我尝试在 viewDidAppear 和 didReceiveMemoryWarning 中访问它(通过模拟内存警告),它仍然没有变成 nil。
  • 奇怪!!当我在实际设备上运行此代码时,它给出了弱实例变量和弱属性的预期结果......这意味着问题仅出在模拟器上。无论如何谢谢@Kunal Shrivastava

标签: ios objective-c memory-management properties


【解决方案1】:

weakStringProperty 不是 nil,因为它的 Foundation 仍在保留它。

当您调用[[NSString alloc]initWithFormat:@"Property"] 时,Foundation 决定将字符串作为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"];

【讨论】:

    【解决方案2】:

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

    例如改为

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

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

    然而,iOS 经常创建永远不会被释放的对象。例如,有 one 个空的 NSArray 对象,它永远不会被释放。许多 NSNumber 对象、短字符串、@YES 和 @NO 以及其他对象也是如此。不能保证一个对象会在你认为会被释放的时候被释放,因此不能保证一个弱对象会变成 nil。

    【讨论】:

    • 在模拟器上...我尝试了您所说的更改,结果...属性在 viewDidLoad 和 viewWillAppear 中仍未设置为 nil,但在 viewDid Appear 中设置为 nil。但奇怪的是,当我在设备上运行它时,所有弱属性在它们指向的对象设置为 nil 并记录预期结果后都设置为 nil。无论如何谢谢 :)
    猜你喜欢
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    相关资源
    最近更新 更多