0

vc2.h

@interface vc2 : UIViewController

@property (nonatomic, strong) NSDictionary *dict;

@end

vc2.m

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.dict = @{@"self":self};
    }
    return self;
}

Root VC

- (void)viewDidLoad {
    [super viewDidLoad];
    vc = [[vc2 alloc]init];
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:YES];
    vc = nil;
}

vc2 strong NSDictionary property holds self and I am setting vc2 to nil in root VC but when I check this in instruments vc2 instance still exists.

When I set weak NSDictionary property vc2 instance gets released after setting it to nil, but Xcode gives me this warning Assigning dictionary literal to a weak property; object will be released after assignment

What is going on regarding this memory management?

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90

1 Answers1

3

Well, if the reference to dictionary is strong, vc2 creates a retain cycle - it references itself through the dictionary. So dropping the reference to it from root won't help, there will still be at least one reference existing - the one from dictionary.

It's simple - if there is a reference to an object, it has to be retained, you cannot release it. Since vc2 holds a reference to the dictionary, the dictionary cannot be released while vc2 exists. However, the dictionary itself holds a reference to vc2, therefore vc2 cannot be released until the dictionary exists. This is the retain cycle - vc2 keeps the dictionary alive, and the dictionary keeps the vc2 alive.

You can break this cycle by using weak reference type - weak means that this reference will not be used to determine if the object has to be retained. From the viewpoint of retaining/releasing the weak references don't count. So when you make the dictionary property weak, you are saying that the vc2 should not keep the dictionary alive. In other words, you are saying that if no other object has a reference to this dictionary, vc2 should not be a reason for retaining it and in such a case the dictionary can be released. BUT, since when you create the dictionary in vc2 the ONLY reference to it is the one in vc2, the weak one, there is no strong reference to it that would prevent releasing it. This results in following:

// here you create a dictionary and assign it to your weak dict property
self.dict = @{@"self":self};
// but right here, after executing it, the only reference to the created dictionary
// is the weak one - that means that the dictionary can be released!
// thus, if you try to print dict right on the next line, it will be nil
// because it was released right after creation

That's the problem with using weak reference to the dictionary. Every object is retained (exists) only when there is at least one strong reference to it. But in this case the poor dictionary will not get a single strong reference to it.

What you want here is a strong reference to a dictionary. That will make sure that the dictionary will exist while the vc2 exists. But you need to break the retain cycle somewhere. To identify what is supposed to be weak is pretty easy: just ask which object is supposed to be dependent on which:

  • Can the dictionary be released, while the vc2 exists?
  • No, it cannot, dictionary should be retained while the vc2 exists.
  • Can the vc2 be released, while the dictionary exists?
  • Yes it can! In fact, when vc2 is released, that's the point when dictionary can be released too.

This means that the dictionary is dependent on the vc2, not vice versa. So you want a strong reference from vc2 to dictionary - that will make sure that while vc2 exists, the dictionary exists. But you don't want the existence of the dictionary to keep the vc2 retained - when other objects release vc2, the dictionary must not hold the vc2 alive. Therefore you need a weak reference from the dictionary to the vc2, not a strong one. That should point you in the right direction - the self reference that you are adding to the dictionary is the one that should be weak.

Check for example this SO question for some advices on how to approach weak entries in a dictionary.

Milan Nosáľ
  • 19,169
  • 4
  • 55
  • 90
  • Thanks for replying can you please tell in bit detail why setting vc to nil will not clear self in dict, dict object is in vc and when the whole class is set to nil why it wont work on dict holding self, is the self in dict is another copy? – Pursuing perfection Jan 03 '18 at 07:43
  • @Pursuingperfection I tried to elaborate on the explanation.. `self` in `dict` is basically another reference to the `vc2`, so if it is `strong`, it will keep the `vc2` around.. – Milan Nosáľ Jan 03 '18 at 08:07
  • @Pursuingperfection glad to help – Milan Nosáľ Jan 03 '18 at 08:39