Present new ViewController after Interstitial Ad is closed - Swift 4 - swift

I am trying to make this button segue to a new ViewController once the user closes the interstitial ad. The segue code works without the ad code and the ad code works without the segue code. Whichever one is put first happens first, but I can't figure out how to get them to work together. You'll notice that I tried moving self.present... to various places with no success (see noted out lines).
#IBAction func adButton(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myVC = storyboard.instantiateViewController(withIdentifier: "newVC")
//self.present(myVC, animated: true, completion: nil)
if (interstitial.isReady) {
interstitial.present(fromRootViewController: self)
interstitial = createAd()
//self.present(myVC, animated: true, completion: nil)
}
self.present(myVC, animated: true, completion: nil)
}

The interstitial object has a delegate (GADInterstitialDelegate) protocol that you can conform to in order to be notified when the ad has been dismissed. There are several delegate methods addressing the ad state which you can review in the documentation.
class ViewController:UIViewController, GADInterstitialDelegate {
override func viewDidLoad() {
super.viewDidLoad()
interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
interstitial.delegate = self
let request = GADRequest()
interstitial.load(request)
}
#IBAction func adButton(_ sender: UIButton) {
if (interstitial.isReady) {
interstitial.present(fromRootViewController: self)
} else {
self.present(myVC, animated: true, completion: nil)
}
}
//Tells the delegate the interstitial is to be animated off the screen.
func interstitialWillDismissScreen(_ ad: GADInterstitial) {
print("interstitialWillDismissScreen")
}
//Tells the delegate the interstitial had been animated off the screen.
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
print("interstitialDidDismissScreen")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myVC = storyboard.instantiateViewController(withIdentifier: "newVC")
self.present(myVC, animated: true, completion: nil)
}
}
Google Ads Docs: Interstitial Ads

Related

Can you change view controllers without segue?

Basically i have a button that changes title, and if the button title is something i want the button to take the user to somewhere different to if the button title was something else
let act1 = act1ViewController()
let act2 = act2ViewController()
override func viewDidLoad() {
super.viewDidLoad()
self.buttonName.setTitle(self.text, for: .normal)
// Do any additional setup after loading the view.
}
#IBAction func buttonPressed(_ sender: UIButton) {
if text == "cheer up" {
self.present(act1, animated: true, completion: nil)
}
else if text == "yay" {
self.present(act2, animated: true, completion: nil)
}
}
Instantiate the ViewController depending on the if check, and present it:
let storyBoard: UIStoryboard = UIStoryboard(name: "MyStoryboard", bundle: nil)
let destinationVC = storyBoard.instantiateViewController(withIdentifier: "ViewControllerIdentifier") as! NewViewController
present(destinationVC, animated: true, completion: nil)
Just remember to set the Identificator in the Storyboard
If the 2 controllers that you want to show are,
class Act1ViewController: UIViewController {
//your code...
}
class Act2ViewController: UIViewController {
//your code...
}
You simply need to put a switch-case on buttonName's title and present the relevant controller act1 or act2. Create act1 and act2 using the storyboard.
#IBAction func buttonPressed(_ sender: UIButton) {
switch sender.titleLabel?.text {
case "cheer up":
if let act1 = self.storyboard?.instantiateViewController(withIdentifier: "Act1ViewController") as? Act1ViewController {
self.present(act1, animated: true, completion: nil)
}
case "yay":
if let act2 = self.storyboard?.instantiateViewController(withIdentifier: "Act2ViewController") as? Act2ViewController {
self.present(act2, animated: true, completion: nil)
}
default:
break
}
}
}
Don't forget to set Act1ViewController and Act2ViewController as storyboardID of the respective controllers in the storyboard.

How do I refresh ViewController after dismiss method is called

For example, I have two viewControllers named A and B. I move to "B view controller" after present method is called. I set some values through UserDefaults.stnadard on "B viewController", and I come back to "A view controller" after dismiss method is called. "A viewController" have to show modified values, but it doesn't show the modified ones. I tried calling viewDidAppear() method on "A viewController", but it didn't work. I tried calling viewDidLoad() method, and it worked well, but I heard that it's not a good way to call the method directly. System can only call it. So, I don't want to call it myself. How should I refresh "A view controller"?
From iOS 13.0 and above, Apple has changed the way viewControllers are presented by default. So, viewWillAppear in ViewControllerA will not be called after dimissing ViewControllerB.
One way for making sure the viewWillAppear method will be called after dismissing ViewControllerB is presenting the viewController setting modalPresentationStyle to fullScreen as:
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ViewControllerB") as! ViewControllerB
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
Sample Code:
ViewControllerA.swift
class ViewControllerA: UIViewController {
private var username: String? {
UserDefaults.standard.string(forKey: "USERNAME")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print(username) //set this to desired view
}
#IBAction func goToViewControllerB(_ sender: UIButton) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ViewControllerB") as! ViewControllerB
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
}
}
ViewControllerB.swift
class ViewControllerB: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UserDefaults.standard.set("John", forKey: "USERNAME")
}
#IBAction func dismiss(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
If you don't want to change the modalPresentationStyle to fullScreen then you can use closures for passing data to ViewControllerA when you're dismissing ViewControllerB.
I think NotificationCenter or prototype would help get this done.
NotificationCenter example
class ViewControllerA: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(testFunc), name: NSNotification.Name(rawValue: "PeformAfterPresenting"), object: nil)
}
#objc func testFunc() {
//TODO: your task
}
}
class ViewControllerB: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func dismiss(_ sender: Any) {
NotificationCenter.default.post(name: "PeformAfterPresenting"), object: nil, userInfo: dataDict)
self.dismiss(animated: true, completion: nil)
}
}
A solid way to handle this would be to set up a protocol & delegate, and call it on ViewControllerB's viewWillDisappear.
In ViewControllerB, set up protocol and delegate property:
protocol ViewControllerBDelegate: AnyObject {
func refreshUserDefaults()
}
weak var delegate: ViewControllerBDelegate?
Also in ViewControllerB, call the method in viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.delegate?.refreshUserDefaults()
}
Then in ViewControllerA, before you present ViewControllerB, assign ViewControllerA as delegate:
let vc = ViewControllerB()
vc.delegate = self
// present as desired
Also in ViewControllerA, conform to ViewControllerB's protocol:
extension ViewControllerA: ViewControllerBDelegate {
func refreshUserDefaults() {
// do whatever you need here
}
}

Swift NavigationController push method request doesn't work from PopUp view

The new PopUp ViewController is presented .overCurrentContext
There are 2 buttons with navigation for 2 other views from PopUp view.
A simple action such as print goes well, but when I try to segue programmatically (from xib file, popUpViewController) nothing happens.
let vc = RegisterEmailViewController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: false)
Goes well from any other view.
What could be wrong?
PopUpViewController code:
// Created by ᴀʟᴇxᴀɴᴅʀ ᴢʜᴇʟɪᴇᴢɴɪᴀᴋ on 23.12.2019.
// Copyright © 2019 ᴀʟᴇxᴀɴᴅʀ ᴢʜᴇʟɪᴇᴢɴɪᴀᴋ. All rights reserved.
import UIKit
class ViewController: UIViewController, Storyboarded {
weak var coordinator: MyCoordinator?
#IBAction func dismissPopUp(_ sender: Any) {
dismiss(animated: false, completion: nil)
}
#IBAction func buttonEmail(_ sender: Any) {
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "EmailViewController") as? EmailViewController
self.navigationController?.pushViewController(vc!, animated: true)
}
#IBAction func buttonPhone(_ sender: Any) {
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "PhoneViewController") as? PhoneViewController
self.navigationController?.pushViewController(vc!, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
There is MyCoordinator which inits all navigations and doesn't let me simply to segue/navigate by my own.
var childCoordinators = [Coordinator]()
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
Therefore, a reference to the controller solved the issue. It is possible to navigate aside, until new subViews, separate views are called.
Code that worked in this case:
let vc = RegisterEmailViewController.instantiate()
vc.coordinator = self
navigationController.pushViewController(vc, animated: false)
Conclusion. Simple there are two ways:
To delete all dependencies and other methods which use
UINavigationController
To declare only by new methods for global usage.

how to close a tabbar swift

I have a login view controller which on a correct login will open a tabbar controller with the following method:
self.dismissViewControllerAnimated(true, completion: { self.loadHomeScreen()})
func loadHomeScreen()
{
emailField.text = ""
passwordField.text = ""
self.presentViewController(UIStoryboard.tabbarController()!, animated: true, completion: nil)
}
private extension UIStoryboard {
class func mainStoryboard() -> UIStoryboard { return UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()) }
class func tabbarController() -> UITabBarController? {
return mainStoryboard().instantiateViewControllerWithIdentifier("TabbarControllerID") as? UITabBarController
}
}
I think my login view controller is still in the background? I have a logout button as the rightbarbutton item on each navbar in my tabgroup. I want to be able to close the tabbar on this button press. How can I achieve this. I can't find any examples. Would I be using a pop command?
UPDATE:
#IBAction func tryLogout(sender: UIBarButtonItem) {
self.dismissViewControllerAnimated(true, completion: nil)
let storyboard = UIStoryboard(name: "main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("login") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}

Content under a login View is visible for a fraction of second

I have a view displaying some content, which is password protected. In viewWillAppear a variable gets checked, to see if the user is properly logged in :
override func viewWillAppear(animated: Bool) {
if (!Config.userLoggedIn) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("loginVC") as! UIViewController
loginVC.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
self.navigationController!.presentViewController(loginVC ,animated: true, completion: nil)
}
}
It works, but the content underneath is visible for a short fraction of a second. How can I present the loginVC without revealing the content underneath.
I cannot put it in viewDidLoadbecause all this is part of a TabBarController, and the views might already be in memory and viewDidLoad is only called once
Simple solution. Hide whole view in viewDidLoad then show it back in viewViewAppear if user is correctly logged in
override func viewDidLoad(){
self.view.hidden = true
}
override func viewWillAppear(animated: Bool) {
if (!Config.userLoggedIn) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("loginVC") as! UIViewController
loginVC.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve
self.navigationController!.presentViewController(loginVC ,animated: true, completion: nil)
}else{
self.view.hidden = false
}
}