0

I need to add a viewcontroller as a subview of mt current view, but cannot deinit after I don't need it anymore

       let viewController = CountrySelectViewController()
        viewController.view.frame = self.view.bounds

        viewController.view.alpha=0

        self.view.addSubview(viewController.view)

        UIView.animate(withDuration: 0.25, delay: 0.0, options: [], animations: {
            viewController.view.alpha=1

        }, completion: { (finished: Bool) in
        })

        viewController.completionHandlerClose = {

            UIView.animate(withDuration: 0.25, delay: 0.0, options: [], animations: {
                viewController.view.alpha=0

            }, completion: { (finished: Bool) in

                viewController.view.removeFromSuperview()
                viewController.view = nil
            })

        }
  • Make it nullable and then if you want to deinit so set it’s value to nil – eemrah Oct 15 '19 at 09:48
  • how can I make it null ? –  Oct 15 '19 at 10:08
  • yourController = nil – eemrah Oct 15 '19 at 10:08
  • 'nil' cannot be assigned to type 'CountrySelectViewController' –  Oct 15 '19 at 10:10
  • 1
    Describe your controller like that var yourController:CountryController? – eemrah Oct 15 '19 at 10:10
  • It worked. Thanks! What is the difference betwwen var viewController:CountrySelectViewController! viewController = CountrySelectViewController() and only var viewController = CountrySelectViewController() ? –  Oct 15 '19 at 10:16
  • The nullable one is optional you can handle it’s reference to be null but other strong definition is controlled by compiler, compiler looks the lifecycle and checks if must be nil or not at the end, like garbage collector – eemrah Oct 15 '19 at 10:17
  • the ! one is that you provide the compiler it’s nullable but it obviously not null, so you have to assign any variable at viewDidLoad or something – eemrah Oct 15 '19 at 10:21

1 Answers1

1

There is an obvious strong reference cycle that has to be broken using weak references:

viewController.completionHandlerClose = { [weak viewController] in
    guard let controller = viewController else { return }
    UIView.animate(
        withDuration: 0.25,
        delay: 0.0,
        options: [],
        animations: {
           controller.view.alpha = 0
        },
        completion: { _ in
            controller.view.removeFromSuperview()
            controller.view = nil
        }
    )
}

See https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • This way, it get deinit just after adding it as a subview and not when I close it... –  Oct 15 '19 at 10:06
  • @F79 It seems you don't know how to work with controllers. Why do you even create a controller if you only use its view? – Sulthan Oct 15 '19 at 10:22
  • It's not just a view, it has methods and other things, this is just because in iOS13 modal views are not full screen, they appear like cards and I need it to appear fullscreen... –  Oct 15 '19 at 10:32
  • @F79 That can be changed using the presentation style of the controller. You are not actually adding the controller to the hierarchy, which is a dangerous thing to do. – Sulthan Oct 15 '19 at 11:03
  • No it cannot be, if you compile with xcode 11 it always get the card look. https://medium.com/@hacknicity/view-controller-presentation-changes-in-ios-13-ac8c901ebc4e –  Oct 15 '19 at 11:25
  • 1
    @F79 You are wrong about that. Only the *default* value has been changed. You can always set it to `.fullScreen` or `.overFullScreen`. The default value is `.automatic`, which on iOS 13 is equal to `.pageSheet`. – Sulthan Oct 15 '19 at 12:12