Zaxter Zaxter - 6 months ago 31
Swift Question

Do I have strong reference cycles here?

I have a

which is subclassed by all other view controllers in my app.

I have some state variables which must be consistent across all view controllers, so I plan to write code for passing back-and-forth these state variables once in the
For this I'm providing a helper function
for forward passing and using
for backward passing.

import UIKit

class BaseViewController: UIViewController, StatePassBackDelegate {

class State {
var connected = false
var loggedIn = false

var state = State()
weak var delegate: StatePassBackDelegate? = nil

// MARK: Lifecycle
override func viewWillDisappear(animated: Bool) {

if self.isMovingFromParentViewController() == true {

// MARK: StatePassBackDelegate functions
func passBackState(state: AnyObject) {
self.state = state as! State

// MARK: Helpers
final func pushStatefulViewControllerWithIdentifier(identifier: String) {
let vc = storyboard?.instantiateViewControllerWithIdentifier(identifier) as! BaseViewController
vc.state = state
vc.delegate = self
navigationController!.pushViewController(vc, animated: true)


protocol StatePassBackDelegate: class {

func passBackState(state: AnyObject)


  1. Do I have strong reference cycles here?

  2. Should I instead use the singleton pattern here?

  1. I don't see retain cycle in your code. If you afraid that some object is not destroying when it's expected, you can log its deallocation to check:

    deinit {
        print("deinit of \(self)")
  2. Agree, that you rather need to introduce some Model level entity for state caring instead of having it on the Controllers layer. Singleton is ok if you don't plan to cover related logic with unit tests.


You can store shared objects in app delegate.

Not sure that I fully understand your app object model. I assumed that the state should be shared across all the app, so better to inject some SystemStateMachine into all interested components. Hope it helps:

    class MyAppDelegate: UIResponder, UIApplicationDelegate {

        var controllersFactory: IViewControllersFactory! = nil

        func applicationDidFinishLaunching(application: UIApplication) {

            let storyboard = UIStoryboard(name:NSBundle.mainBundle().infoDictionary!["UIMainStoryboardFile"] as! String , bundle: NSBundle.mainBundle())
            controllersFactory = ViewControllersFactory(storyboard: storyboard, stateMachine: SystemStateMachine())

    struct SystemState : OptionSetType {
        let rawValue: Int

        static let None   = SystemState(rawValue: 0)
        static let Connected = SystemState(rawValue: 1 << 0)
        static let LoggedIn  = SystemState(rawValue: 1 << 1)


    protocol ISystemStateMachine {

        var currentState: SystemState { get set }

    class SystemStateMachine: ISystemStateMachine {

        var currentState: SystemState = .None

    protocol IViewControllersFactory {

        func instantiateViewController(identifier: String) -> BaseViewController?

    class ViewControllersFactory: IViewControllersFactory {

        let _storyboard: UIStoryboard
        let _stateMachine: ISystemStateMachine

        init(storyboard: UIStoryboard, stateMachine: ISystemStateMachine) {
            _storyboard = storyboard
            _stateMachine = stateMachine

        func instantiateViewController(identifier: String) -> BaseViewController? {
            if let vc = _storyboard.instantiateViewControllerWithIdentifier(identifier) as? BaseViewController {
                vc.stateMachine = _stateMachine
                return vc
            return nil

    class BaseViewController: UIViewController {

        var stateMachine: ISystemStateMachine!

        // MARK: Lifecycle
        func somethingWorthHappen() {
            //switch state
        func somethingWorth2Happen() {
            //switch state

            guard let appDelegate = UIApplication.sharedApplication().delegate as? MyAppDelegate else {
                //log an error
            if let vc = appDelegate.controllersFactory.instantiateViewController("myViewController") {
                navigationController!.pushViewController(vc, animated: true)