1

I have a lot of view controllers that use the same two functions that show and hide popup for me. Everytime I use them, I ask myself if it wouldn't be better to put them in a global class called PopupUtils for example and set the functions as static functions.

I did it and it worked but I'm not sure if it's a good thing to do because I have to pass to my function three arguments: the parent view controller, the child view controller and the popup_container view

Since it's all passed by val, is there not a problem with memory ? or any other problem I should be aware of ?

Here is my static class called Popup Utils

class PopupUtils {

 static func showPopupView(parentViewController: UIViewController, childViewController: UIViewController, popupContainer: UIView) {


        parentViewController.addChild(childViewController)

        popupContainer.addSubview(childViewController.view)

        childViewController.view.frame = popupContainer.bounds
        childViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        childViewController.didMove(toParent: parentViewController)

        UIView.transition(with: popupContainer, duration: 0.2, options: .transitionCrossDissolve, animations: {
            popupContainer.isHidden = false
        })

    }


    static func removePopupView(childViewController: UIViewController, popupContainer: UIView){

        // Remove pop up VC from children
        childViewController.willMove(toParent: nil)
        childViewController.view.removeFromSuperview()
        childViewController.removeFromParent()

        // Hide pop up container
        popupContainer.isHidden = true

        // Release language menu
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "releaseMenuSwipe"), object: nil)

    }
}
EtienneG
  • 13
  • 2
  • why don't you present the popup instead of embedding it? – farhad Jan 29 '20 at 08:45
  • I didn't know there was another solution. How can I present the popup ? – EtienneG Jan 29 '20 at 08:51
  • https://stackoverflow.com/questions/34149386/are-static-methods-always-held-in-memory This might be helpful regarding static functions. – Abdul Karim Khan Jan 29 '20 at 08:52
  • You can create new UIViewController in Storyboard, and present that from previous screen. Then select your Previous ViewController -> Attribute Inspector -> Set transition Style to "cross dissolve". And Set Presentation to "current content". – Abdul Karim Khan Jan 29 '20 at 08:58
  • if you set ```modalPresentationStyle ``` of popupVC to ```.overFullScreen ``` and then present it previous VC would be visible just make sure background of popupVC is transparent – farhad Jan 29 '20 at 09:01
  • I think I see what you mean, but then if I have the same pop up over various viewController, do I have to link the pop up to all viewControllers it will be possibly laid over ? – EtienneG Jan 29 '20 at 15:00

2 Answers2

2

It’s not really bad but how about an extension of UIViewController

extension UIViewController {

    func showPopupView(childViewController: UIViewController, popupContainer: UIView) {
        addChild(childViewController)
        popupContainer.addSubview(childViewController.view)
        childViewController.view.frame = popupContainer.bounds
        childViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        childViewController.didMove(toParent: self)

        UIView.transition(with: popupContainer, duration: 0.2, options: .transitionCrossDissolve, animations: {
            popupContainer.isHidden = false
        })
    }

    func removePopupView(childViewController: UIViewController, popupContainer: UIView) {

        // Remove pop up VC from children
        childViewController.willMove(toParent: nil)
        childViewController.view.removeFromSuperview()
        childViewController.removeFromParent()

        // Hide pop up container
        popupContainer.isHidden = true

        // Release language menu
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "releaseMenuSwipe"), object: nil)

    }
}

An alternative to get rid of the parameters is a protocol extension. It assumes that the adopting UIViewController has two properties popupContainer and childViewController, if they are optional change and handle the type accordingly.

The two methods in the extension are available for any UIViewController which adopts the protocol

protocol PopupManageable {
    var popupContainer: UIView { get }
    var childViewController: UIViewController { get }
}

extension PopupManageable where Self : UIViewController {

    func showPopupView() {
        self.addChild(childViewController)
        popupContainer.addSubview(childViewController.view)
        childViewController.view.frame = popupContainer.bounds
        childViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        childViewController.didMove(toParent: self)

        UIView.transition(with: popupContainer, duration: 0.2, options: .transitionCrossDissolve, animations: {
            self.popupContainer.isHidden = false
        })
    }

    func removePopupView() {

        // Remove pop up VC from children
        childViewController.willMove(toParent: nil)
        childViewController.view.removeFromSuperview()
        childViewController.removeFromParent()

        // Hide pop up container
        popupContainer.isHidden = true

        // Release language menu
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "releaseMenuSwipe"), object: nil)

    }
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Looks like a very good idea, I didn't know much about protocols, I'm going to test that :) Thank you for your help – EtienneG Jan 29 '20 at 15:00
0

I think you have to keep everything tracked. You are passing the view controller around and adding a child view controller. This may lead to the memory leak if you are not aware of complexity in the future. Keep tracking allocation whenever you add new task. in it.

Paresh. P
  • 486
  • 5
  • 18