Tuesday, November 3, 2015

Using completion block to detect dismissViewControllerAnimated of ViewControllerB in ViewControllerA

Update: August 3, 2017 (Swift 3.1 + Xcode 8.3.3)
Original Post: November 3, 2015 (Swift 2)

If I have a default ViewControllerA, which presents ViewControllerB with 'OverCurrentContext' UIModalPresentationStyle, then I face a problem that 'viewWillAppear' in ViewControllerA is not called after ViewControllerB is dismissed. Consequently, it would be difficult for me to run some codes in ViewControllerA since I don't know when ViewControllerB is dismissed. 

Here is my original description to this problem:

iOS: Detect dismissViewControllerAnimated while using UIModalPresentationStyle.OverCurrentContext

In order to run some codes in ViewControllerA right after ViewControllerB is dismissed, a completion block is created in ViewControllerB. Then function myFuncInViewControllerA() in ViewControllerA can be executed at the right moment. The solution is as below:

Update: August 3, 2017 (Swift 3.1 + Xcode 8.3.3)

Remember to select ViewControllerA.swift as a custom class in the identify inspector in the storyboard after renaming ViewController.swift as ViewControllerA.swift.



ViewControllerA.swift:


import UIKit

class ViewControllerA: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(frame: CGRect(x: (view.frame.width-200)/2, y: 50, width: 200, height: 20))
        button.setTitle("Button", for: UIControlState.normal)
        button.setTitleColor(UIColor.blue, for: UIControlState.normal)
        button.setTitleColor(UIColor.cyan, for: UIControlState.highlighted)
        button.contentMode = UIViewContentMode.center
        button.addTarget(self, action: #selector(btnPressed), for: UIControlEvents.touchUpInside)
        view.addSubview(button)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print("viewWillAppear")
    }
    
    func btnPressed() {
        let controllerB = ViewControllerB()
        controllerB.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
        controllerB.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
        
        controllerB.dismissVCCompletion(){ () in
            self.myFuncInViewControllerA()
        }
        
        present(controllerB, animated: true, completion: nil)
    }
    
    func myFuncInViewControllerA() {
        print("Back to ViewControllerA!")
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

ViewControllerB.swift:


import UIKit

class ViewControllerB: UIViewController {
    
    typealias typeCompletionHandler = () -> ()
    var completion : typeCompletionHandler = {}
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(white: 0, alpha: 0.5)
        
        let viewB = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width*0.6, height: view.frame.height*0.6))
        viewB.center = view.center
        viewB.backgroundColor = UIColor.orange
        
        let buttonBack = UIButton(frame: CGRect(x: (viewB.frame.width-200)/2, y: 100, width: 200, height: 20))
        buttonBack.setTitle("Back", for: UIControlState.normal)
        buttonBack.setTitleColor(UIColor.blue, for: UIControlState.normal)
        buttonBack.setTitleColor(UIColor.cyan, for: UIControlState.highlighted)
        buttonBack.contentMode = UIViewContentMode.center
        buttonBack.addTarget(self, action: #selector(btnBackPressed), for: UIControlEvents.touchUpInside)
        viewB.addSubview(buttonBack)
        
        view.addSubview(viewB)
    }
    
    func btnBackPressed() {
        dismiss(animated: true, completion: {
            self.completion()
        })
    }
    
    func dismissVCCompletion(completionHandler: @escaping typeCompletionHandler) {
        self.completion = completionHandler
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

Result:


Original Post: November 3, 2015 (Swift 2)

ViewControllerA.swift:


class ViewControllerA: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let button = UIButton(frame: CGRectMake(50, 100, 200, 20))
        button.setTitle("Button", forState: UIControlState.Normal)
        button.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        button.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        button.addTarget(self, action: "btnPressed:", forControlEvents: UIControlEvents.TouchUpInside)
        view.addSubview(button)
        
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        print("viewWillAppear")
    }
    
    func btnPressed(sender: UIButton) {
        let controllerB = ViewControllerB()
        controllerB.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
        controllerB.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
        
        controllerB.dismissVCCompletion(){ () in
            self.myFuncInViewControllerA()
        }

        presentViewController(controllerB, animated: true, completion: nil)
    }
    
    func myFuncInViewControllerA() {
        print("Back to ViewControllerA!")
    }

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


ViewControllerB.swift:

class ViewControllerB: UIViewController {

    typealias typeCompletionHandler = () -> ()
    var completion : typeCompletionHandler = {}
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor(white: 0, alpha: 0.5)
        
        let viewB = UIView(frame: CGRectMake(0,0,view.frame.width*0.6,view.frame.height*0.6))
        viewB.center = view.center
        viewB.backgroundColor = UIColor.orangeColor()

        let buttonBack = UIButton(frame: CGRectMake(30, 100, 200, 20))
        buttonBack.setTitle("Back", forState: UIControlState.Normal)
        buttonBack.setTitleColor(UIColor.blueColor(), forState: UIControlState.Normal)
        buttonBack.setTitleColor(UIColor.cyanColor(), forState: UIControlState.Highlighted)
        buttonBack.addTarget(self, action: "btnBackPressed:", forControlEvents: UIControlEvents.TouchUpInside)
        viewB.addSubview(buttonBack)
        
        view.addSubview(viewB)
    }
    
    func btnBackPressed(sender: UIButton) {
        dismissViewControllerAnimated(true, completion: {
            self.completion()
        })
    }
    
    func dismissVCCompletion(completionHandler: typeCompletionHandler) {
        self.completion = completionHandler
    }

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

}

References:

No comments:

Post a Comment