How to Show Viewcontroller from a Non-Viewcontroller Helper Class

How to show ViewController from a non-ViewController helper class?

You can show your viewController from helper class as root view controller of navigationcontroller

UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]];

UINavigationController *controller = (UINavigationController*)[storyBoard
instantiateViewControllerWithIdentifier: @"RootNavigationController"]; //set storyboard ID to your root navigationController.

YourViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:@"YourViewController"]; // //set storyboard ID to viewController.
[controller setViewControllers:[NSArray arrayWithObject:vc] animated:YES];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController=controller;

Present View Controller From outside of controller with out passing self reference

You can use this extension

extension UIApplication
{
class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController?
{
if let nav = base as? UINavigationController
{
let top = topViewController(nav.visibleViewController)
return top
}

if let tab = base as? UITabBarController
{
if let selected = tab.selectedViewController
{
let top = topViewController(selected)
return top
}
}

if let presented = base?.presentedViewController
{
let top = topViewController(presented)
return top
}
return base
}

}

then you can use this code to present your controller from anywhere

let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let viewController = storyboard.instantiateViewController(withIdentifier: "AccountLockedController") as! AccountLockedController
UIApplication. topViewController()?.present(viewController, animated: true) {
print("Presented")
}

Access UIViewController from Utility Class

You can pass your UIViewController to the onclick function such as:

 static func ClickAction(Button: Button, viewController: UIViewController) {
//...
viewController.present(...
}

Access a UIViewController class property without casting?

You still need to cast using as? ..., however in order not to do that for all view controllers that have the bgButton, you can define a base protocol enforcing all classes conforming to it to have the bgButton:

public protocol Buttoned {
var bgButton: UIButton { get set }

func setHideButton(_ isHidden: Bool)
}

extension Buttoned {
public func setHideButton(_ isHidden: Bool) {
bgButton.isHidden = isHidden
}
}

public class AddNewViewController: Buttoned {
@IBOutlet fileprivate weak var bgButton: UIButton!
....
}

public class EditViewController: Buttoned {
@IBOutlet fileprivate weak var bgButton: UIButton!
....
}

then you can handle the action in the actual view controller like below:

func showHideDetails(controller: UIViewController, isHidden: Bool) {
...
if let controller = controller as? Buttoned {
controller.setHideButton(isHidden)
}
...
}

show UIAlertController outside of ViewController

I wrote this extension over UIAlertController to bring back show().

It uses recursion to find the current top view controller:

extension UIAlertController {

func show() {
present(animated: true, completion: nil)
}

func present(animated: Bool, completion: (() -> Void)?) {
if let rootVC = UIApplication.shared.keyWindow?.rootViewController {
presentFromController(controller: rootVC, animated: animated, completion: completion)
}
}

private func presentFromController(controller: UIViewController, animated: Bool, completion: (() -> Void)?) {
if
let navVC = controller as? UINavigationController,
let visibleVC = navVC.visibleViewController
{
presentFromController(controller: visibleVC, animated: animated, completion: completion)
} else if
let tabVC = controller as? UITabBarController,
let selectedVC = tabVC.selectedViewController
{
presentFromController(controller: selectedVC, animated: animated, completion: completion)
} else if let presented = controller.presentedViewController {
presentFromController(controller: presented, animated: animated, completion: completion)
} else {
controller.present(self, animated: animated, completion: completion);
}
}
}

Now it's as easy as:

var alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
alertController.show()

How to present UIAlertController when not in a view controller?

I posted a similar question a couple months ago and think I've finally solved the problem. Follow the link at the bottom of my post if you just want to see the code.

The solution is to use an additional UIWindow.

When you want to display your UIAlertController:

  1. Make your window the key and visible window (window.makeKeyAndVisible())
  2. Just use a plain UIViewController instance as the rootViewController of the new window. (window.rootViewController = UIViewController())
  3. Present your UIAlertController on your window's rootViewController

A couple things to note:

  • Your UIWindow must be strongly referenced. If it's not strongly referenced it will never appear (because it is released). I recommend using a property, but I've also had success with an associated object.
  • To ensure that the window appears above everything else (including system UIAlertControllers), I set the windowLevel. (window.windowLevel = UIWindowLevelAlert + 1)

Lastly, I have a completed implementation if you just want to look at that.

https://github.com/dbettermann/DBAlertController

Dismiss View Controller Doesn't Working in Helper Class Swift

After two days finding the right way to dismiss my controller and couldn't find any because I think Xcode find that my current controller is nil. Instead, I use this:

let viewController = UIStoryboard(name: "DashboardPreLogin", bundle: Bundle.main).instantiateViewController(withIdentifier: "TabBarPreLoginViewController")

let appDel: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appDel.window?.rootViewController = nil
appDel.window?.rootViewController = viewController
UIView.transition(with: appDel.window!, duration: 0.5, options: UIViewAnimationOptions.transitionCrossDissolve, animations: {() -> Void in appDel.window?.rootViewController = viewController}, completion: nil)

This will dismissing view controller and replace with new controller.



Related Topics



Leave a reply



Submit