circular reference

This code seem to create a circular reference :


class archeryModel
{
...
hidden var _shotProcess = null;
....

function initialize() {
...........
_shotProcess = new ShotProcess(self);
}

}

class ShotProcess {
....
var _model;
...
function initialize(model) {
_model = model; // seems to cause circular ref !
...
}



but i don't understand, how can i wrote it differently !
note : i've try to use _model = Application.getApp().model; instead, but in that case, when I call some functiojn in the model (like _model.myFunc() ) it exit wit ha non existent function !


  • Hi FlowState ,
    Do you have the sample but with callbacks ?

    Please send it by private message and I'll try to help you :)
  • MarkusGL thanks, but I was just commenting on vald70 ’s situation. I don’t have this problem myself. But I don’t see how a callback can resolve the issue of circular references since it needs the reference to the object to make the function call....

    I see a few possibilities here:
    - ignore the circular reference (if you just have one of each object and they last for the entire lifetime of the app maybe it doesn’t matter)
    - rearchitect the code so you don’t have circular references
    - Use weak reference (haven’t tried this myself, but it seems like this is the solution for circular references)
  • Just to help: create a new App project and paste this quick and dirty example just to test.
    This doesn't create Circular Dependencies (tested :) ).

    EDIT : As FlowState points on the next post, this code creates Circular Dependencies. Please look at his solution.

    using Toybox.WatchUi;
    using Toybox.System as Sys;

    class TestCircularDpsView extends WatchUi.View {

    var _archeryModel1, _archeryModel2;

    function initialize() {

    View.initialize();

    _archeryModel1=new ArcheryModel("model1");
    _archeryModel2=new ArcheryModel("model2");
    }

    function onLayout(dc) {

    setLayout(Rez.Layouts.MainLayout(dc));
    }
    }



    class ArcheryModel {

    hidden var _shotProcess = null;
    hidden var _model="";

    function initialize(model) {

    _model=model;
    _shotProcess = new ShotProcess(method(:onShot));
    }

    function onShot() {
    Sys.println("Hello "+_model);
    }

    }


    class ShotProcess {

    hidden var _callBackMethod;

    function initialize(callBackMethod) {
    _callBackMethod=callBackMethod;
    triggerCallBack();
    }

    function triggerCallBack()
    {

    if(_callBackMethod!=null) {
    _callBackMethod.invoke();
    }
    }
    }

  • MarkusGL, I think that sample code creates circular references, in the implicit object reference contained in the callback method. Tested on simulated VA3. [IMG2=JSON]{"data-align":"none","data-size":"full","src":"https:\/\/i.postimg.cc\/PrzcHDyh\/circ.png"}[/IMG2]
    Here's my modified version of the sample code, with weak references. Seems to work and seems to avoid circular references.

    using Toybox.WatchUi;
    using Toybox.System as Sys;

    class TestCircularDpsView extends WatchUi.View {
    var _archeryModel1, _archeryModel2;

    function initialize() {
    View.initialize();
    _archeryModel1 = new ArcheryModel("model1");
    _archeryModel2 = new ArcheryModel("model2");
    }
    }

    class ArcheryModel {
    hidden var _shotProcess = null, _model = "";

    function initialize(model) {
    _model = model;
    // Pass in a "weak reference" to self, which will not
    // count for the purposes of reference counting and automatic
    // freeing of memory
    _shotProcess = new ShotProcess(self.weak());
    }

    function onShot() {
    Sys.println("Hello " + _model);
    }
    }

    class ShotProcess {
    hidden var _archeryModelWeakRef;

    function initialize(archeryModelWeakRef) {
    _archeryModelWeakRef = archeryModelWeakRef;
    archeryModel_OnShot();
    }

    function archeryModel_OnShot() {
    var archeryModelStrongRef = _archeryModelWeakRef.get();
    // Technically, the null check is only necessary if this function is called
    // in a context where the referenced object may no longer exist.
    // In this example, that will not happen, but in general it could happen
    if (archeryModelStrongRef != null) {
    archeryModelStrongRef.onShot();
    }
    }
    }
  • Ouch... I'm sorry. You are right!
    I knew about weak references but I never used. Your example is very didactic :)

    Thanks for sharing!
  • MarkusGL no worries!


    I will try with weak reference as I've already try with method which as you said create circular reference from implicit object being called !

    Now : should <<i worry about these circular reference, as these object are the only one created at startup of my app ?
  • vald70 I could be wrong, but I don't think it matters in your case. I think it would only matter if you needed to get rid of one or both objects during the app lifetime, and you wanted the associated memory to be freed. When app closes all memory should be freed anyway, regardless of circular references.

    (Please correct me if I'm wrong, any CIQ experts reading this!)

    In general it's probably good practice to avoid this kind of circular reference, but I think it's harmless in this specific case.
  • vald70In general it's probably good practice to avoid this kind of circular reference, but I think it's harmless in this specific case.

    Yes. Often you can configure circular references like this (that are in place for the life of the app) in App.onStart() and break them in App.onStop().

  • Travis.ConnectIQ but I'm curious what would happen (if anything) if you just ignored the circular references and let the app exit. Would anything bad happen? Would the existence of circular references prevent the app from cleaning up properly or would the app just exit normally?

    BTW, breaking circular references in App.onStop() is the best solution I've heard so far. Seems like a lot less overhead/effort than adding weak reference code everywhere you have a circular reference. I’m just wondering if it’s strictly necessary.