0

I consider whether it is possible to return from function child object created inside parent object that will keep reference to its parent and prevent parent from being deallocated from memory. Simultaneously I don't want to have retain cycle and memory leak.

class ObjectA { 
   let objectB = ObjectB()
}

class ObjectB { 

}

func factoryFunc() -> ObjectB { 
   ObjectA().objectB
}

Client code

let objB = factoryFunc() 
// but keep also ObjectA as long as objB lives 
// but do not create retain cycle
// I do not want to return ObjectA and do not want to manage it outside of black box factory method. 

I could add

class ObjectB { 
    var parent: ObjectA?
}

It creates retain cycle and memory leak

class ObjectB { 
        weak var parent: ObjectA?
    }

This doesn't prevent deallocation of ObjectA

Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143
  • Must ObjectA hold a reference to ObjectB? – Joakim Danielson Sep 21 '20 at 16:58
  • I think yes as in reality it is flow controller that has objectB as rootViewController so objectB is used to push new controllers. I could return this flowController but it makes sense only in the case of one of apps. In other apps that use this I prefer to directly return rootViewController but still reuse this flowcontroller navigations. – Michał Ziobro Sep 21 '20 at 17:04
  • Can you make the ObjectB reference "weak" inside the so-called parent ObjectA? – RookiePro Sep 21 '20 at 17:14
  • If it's a matter of flow, you could indeed create a strong reference and handle memory cleanup in `viewWillDisappear` or some other _let's call it flowcycle_ method. – Andreas Oetjen Sep 21 '20 at 19:37
  • I can make retain cycle and then break it in viewWillDisappear like assigning nil to var parentObjA: ObjectA . Hm it is nice idea. But finally I created ObjectC that holds both ObjectA and ObjectB. C is NavigationController that holds FlowController and use it's rootViewController as rootViewController of NavigationController – Michał Ziobro Sep 21 '20 at 20:55

1 Answers1

0

There would be no other way than by creating a strong reference cycle. But if you reach this, there might be an issue in the design; you should never be needed to create a strong reference cycle. In your case:

  1. Maybe you should not use ObjectB directly, but rather through some designed interface of ObjectA.

  2. If you need only ObjectB specifically, then you don't need ObjectA.

  3. If ObjectA is so important in your application, then you should manage it outside of that factory.

If you don't need to use ObjectA (as you don't want it returned), and you won't manage it outside that scope, then you certainly don't need it at all and you will be able to move your logic outside that class (or maybe inherit ObjA in ObjB).

If you need it in some other hidden way anyways, then you should create some kind of controller or manager that manages this whole flow where you use the classes.

Also, very important, keep in mind that the ownership must go only one way, never both ways, and, almost always, the control flow in the same way as the ownership. If ObjectA is the parent of ObjectB, then ObjectB should know absolutely nothing about ObjectA.

Vlad Rusu
  • 1,414
  • 12
  • 17
  • 1
    ObjectA is sub FlowController and ObjectB is rootViewController. FlowController manages navigation of this part of app childviews of ObjectB. So Flow is important. But on the other hand I do not want to return entire FlowController but just rootViewController but keeping navigation logic in this flowController. Maybe I should make wrapping ViewController or NavigationController that has reference to flow controller and adds this rootViewController as its root – Michał Ziobro Sep 21 '20 at 17:47
  • A flow controller in this case should be some kind of singleton and should manage the root view controller. You should be able to reach the flow controller from everywhere and then the flow controller should be responsible for creating the root view controller. Try to keep the hierarchy in your dependency. Another approach would be to swap the ownership, meaning that the root view controller has a flow controller and asks it how it should manage the flow. – Vlad Rusu Sep 22 '20 at 07:12