0
votes

My initial GameViewController has a delegate property of a GameDelegate. I'm setting this property in the AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    //Set initial view controller
    window = UIWindow(frame: UIScreen.main.bounds)
    if let window = window {
        let gameTracker = GameTracker()
        let gameViewController = GameViewController()
        gameViewController.delegate = gameTracker
        window.rootViewController = gameViewController
        window.makeKeyAndVisible()
    }
    return true
}

This only works since my delegate is strong:

class GameViewController: UIViewController{

        var delegate: GameDelegate?

        var gameScore: GameScore {
            return (delegate!.gameScore)
        }

        override func viewDidLoad() {
            super.viewDidLoad()
        }
    }

Using a weak delegate will cause the App to crash since delegate will be nil after the GameViewController is presented.

My question is: Is this approach safe, and if not, how should it be done? I've read about delegates and it's recommend to keep it as a weak var to prevent a retain cycle. I'm not using Storyboards.

2

2 Answers

2
votes

The problem is that you are declaring the gameTracker in a function, rather than as a class-level variable. The AppDelegate's reference to it is released immediately when the function exits, leaving your GameViewController with the only reference to it.

The way to solve this is to declare gameTracker as a class-level variable in your AppDelegate:

var gameTracker: GameTracker?

You need to declare it as an optional, since you only want to instantiate it when your if condition is met:

if let window = window {
    self.gameTracker = GameTracker()
    let gameViewController = GameViewController()
    gameViewController.delegate = self.gameTracker
    window.rootViewController = gameViewController
    window.makeKeyAndVisible()
}

If you do this, you will be able to declare your delegate as weak in your GameViewController.

1
votes

Safe approach is using weak delegate. If you handle nil then it shouldn't be a problem.

weak var delegate: GameDelegate?

var gameScore: GameScore? {
    return delegate?.gameScore
}

Do you intent on calling 'delegate' when 'gameScore' changes? If you want to save 'gameScore' and as well as return 'delegate' then you should use property observer.

var gameScore: GameScore {
    didSet {
        delegate?.gameScore
    }
}