Search code examples
iosswiftreferenceone-to-manyweak

Weak Refrence in class return nil when created in first class's init


im trying to create weak reference class in another class, in first class's init i create instance of second class to use it in a function, but after init function is done , second class get destroyed and return nil, here's a example code

//: Playground - noun: a place where people can play

import UIKit

class A {
    weak var b : B?
    init(){
        NSLog("a Created")
        self.b = B()
    
    }
    deinit{
        NSLog("a Destroyed")
    }
}

class B {
    var arrayOfA : Array <A> = []
    init(){
        NSLog("b Created")
       
    }
    deinit{
           NSLog("b Destroyed")
    }
    func printSomething(){
        NSLog("print Something")
    }
}


func test(){
    let a : A = A()
    a.b?.printSomething()
    NSLog("still in test()")
}

test()

in console i see this

2016-04-04 00:34:50.516 MyPlayground[20009:921709] a Created

2016-04-04 00:34:50.516 MyPlayground[20009:921709] b Created

2016-04-04 00:34:50.516 MyPlayground[20009:921709] b Destroyed

2016-04-04 00:34:50.527 MyPlayground[20009:921709] still in test()

2016-04-04 00:34:50.527 MyPlayground[20009:921709] a Destroyed

and calling printSomething() will return nil

i dont want create B class outside of A class and also i want it weak for memory leak problems.

some how i want one to many relationship between two swift class , so i can load data from function


Solution

  • Since you declare b as weak, it gets deallocated as soon as it goes out of scope. In this case, as soon this code:

    init(){
      NSLog("a Created")
      self.b = B()
    }
    

    finishes execution, self.b gets destroyed. This is the expected behavior. If you want b to hang around after the init then you should leave it as strong.

    Alternatively you can do this:

    func test(){
      let b : B = B()
      let a : A = A(b:b)
      a.b?.printSomething()
      NSLog("still in test()")
    }
    

    In A you can make a special init that takes in a B:

    init(b: B){
      NSLog("a Created")
      self.b = b
    }
    

    With this code, A's reference to B is still weak, but since the B is still around in the test() method, it's also there when printSomething() is called.