Dipika
Dipika

Reputation: 1127

why weak for property and __weak for instance variable behave differentenly

I know that strong and weak are modifiers used in property declarations while __strong and __weak are used in declarations of instance variables... strong says that keep the object in memory as long as i m owning it and weak says that keep the object in memory as long as someone else having a strong reference to it... right? but i not getting why weak for property and __weak for instance variable behaves differently ?? Here is what i wondered...

 @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

And here are the resulted logs

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.   ——??

Both weak instance variables print (null) after the objects they were weakly referring to, are set to nil and this's as expected but i m wondering why both the weak properties weakStringProperty and weakArrayProperty are still print their previous values and behaving like they were strongly pointing to strongStringProperty and strongArrayProperty respectively??

Thanks :)

Upvotes: 6

Views: 790

Answers (2)

gnasher729
gnasher729

Reputation: 52538

Your properties are atomic, because you didn't declare them nonatomic. Atomic properties return an object that is retained and autoreleased, so the object will remain in the autorelease pool and very remain retained until you exit the viewDidLoad method.

Change for example to

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

and you are more likely to get the expected result. Or check the properties in another method later, and the weak properties will likely be nil.

However, iOS quite often creates objects that will never be released. For example, there is one empty NSArray object which will never, ever be released. Same for many NSNumber objects, short strings, @YES and @NO and others. There is no guarantee that an object will be deallocated when you think it would be, and therefore no guarantee that a weak object becomes nil.

Upvotes: 1

Brian Nickel
Brian Nickel

Reputation: 27550

weakStringProperty isn't nil because it Foundation is still retaining it.

When you called [[NSString alloc]initWithFormat:@"Property"], Foundation decided to intern the string as a NSTaggedPointerString which it then retained for future use. You can validate this by logging the class:

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

I'm not sure what all criteria the system uses to decide to create these strings, but length and mutability are factors. Either of the following would get your desired result.

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

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

Upvotes: 1

Related Questions