Presenting the new controller programatically in ios swift only displaying blank screen - ios

I am developing a simple IOS application using swift. In my application I need to open new controller programatically from another controller. So I added another scene to the storyboard.
This is the screenshot
Then I added a new class for new controller which is inheriting from the UIViewController. This is the code for new controller
import UIKit
class ReplayController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Then, I tried to open the new controller view (ReplayController) from the main controller like this in code.
func gameOver()
{
let replayController = ReplayController()
present(replayController, animated: true, completion: nil)
}
When I call that function, it just pops up the blank screen. Nothing appear on the screen. What is wrong and how can I solve it?

In your Storyboard file, ensure the ReplayController has its 'File's Owner' set to your ReplayController class. Then set the Storyboard ID like below:
Then you can load it like so:
let replay = storyboard?.instantiateViewController(withIdentifier: "ReplayController") as! ReplayController
self.present(replay, animated: true, completion: nil)

You have to reference it with id in storyboard
let replayController = self.storyboard?.instantiateViewController(withIdentifier: "replayControllerID") as! ReplayController
present(replayController, animated: true, completion: nil)
as this line only
let replayController = ReplayController()
doesn't load the xib or storyboard object associated with the VC

When you design your view controllers in storyboard, you need to programatically create them using the method instantiateViewController of class UIStoryboard to access it along with all the outlets.
Before that, you need to set the Storyboard ID of the respective view controller in your storyboard like this:
And then present it:
func gameOver() {
if let myVC = storyboard?.instantiateViewController(withIdentifier: "ViewController") {
self.present(myVC, animated: true, completion: nil)
}
}

Related

Present view controller within details view controller of master details view controller in swift 3

I have some problem to present a view controller within details view controller of master details view controller. Is it possible to do that?
I want to present a view controller when the user taps a button on details view controller exactly like details view controller though it is not.
If it is possible then help me. If not then guide me some way to do that.
You can try it from Storyboard like,
In the storyboard, select the Segue as present modally, and go to the Identity Inspector, and choose Current Context for the Presentation option.
Hope it helps.
It's possible, but your details VC must be a navigation Controller, so you can present.
Try this :
class func presentViewCoontroller(vc : UIViewController) -> Void{
let viewController : UIViewController = ((UIApplication.shared.delegate as! AppDelegate).window?.rootViewController)!
if (viewController.presentedViewController != nil) {
viewController.presentedViewController?.present(vc, animated: true, completion: nil)
}
else{
viewController.present(vc, animated: true, completion: nil)
}
}
Calling
self.presentViewCoontroller(vc: yourcontroller)
create a static instance of master view controller and then try to present a new view controller with that reference.
class MasterViewController : UIViewController{
static var masterVC : UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
MasterViewController.masterVC = self
}
}
class DetailViewController : UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func didTapButton(_ sender: UIButton) {
MasterViewController.masterVC?.present(<newViewController>, animated: true, completion: nil)
}
}

Add Tab Bar Programmatically to ViewController

I have a TabBarController in my Main.storyboard file.
In my Upload.storyboard I am presenting a ViewController from the Main.storyboard file, however, it doesn't contain the tab bar.
The viewProfile button should go to a tab called Sharks and within that present a view controller based on data gathered in the Upload.storyboard (modal view).
Can I add the tab bar programmatically or am I not properly presenting the correct VC?
// MARK: - Actions
#IBAction func viewProfileButtonPressed(_ sender: UIButton) {
let stb = UIStoryboard(name: "Main", bundle: nil)
let sharkProfile = stb.instantiateViewController(withIdentifier: "sharkProfile") as! SharkProfileTableViewController
self.present(sharkProfile, animated: true) {
// add tab bar here?
}
}
What you need to do is present the tab bar view controller, not the view controller that is embedded in it
One method is to create a Delegate Protocol to allow a tap on View Profile button to "call back" to the View Controller that presented it. When that callback is received, the VC sets the "current" tab.
It will look something like this:
// define "call back" delegate protocol
protocol EncounterUploadedDelegate : class {
func didTapSharkProfileButton()
}
The Encounter view controller will need to conform to that protocol:
class EncounterViewController: UIViewController, EncounterUploadedDelegate {
// the normal stuff for this VC and all the other code for it
// ...
// conform to the protocol
func didTapSharkProfileButton() -> Void {
// when we get this call-back, switch to the Shark Profile tab
// tabs are zero-based, so assuming "SharkProfile" is
// is the 4th tab...
self.tabBarController?.selectedIndex = 3
}
// assuming a "Show Modal" segue named "ShowEncounterUploadSegue" is used
// to present the Modal View
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEncounterUploadSegue" {
let vc = segue.destination as! TabModalVC
vc.encounterDelegate = self
}
}
}
The view controller to be presented as modal:
class TabModalVC: UIViewController {
weak var encounterDelegate: EncounterUploadedDelegate?
#IBAction func profileButtonTapped(_ sender: Any) {
// dismiss self (the modal view)
self.dismiss(animated: true, completion: nil)
// this will call back to the delegate, if one has been assigned
encounterDelegate?.didTapSharkProfileButton()
}
}
Hope that all makes sense :)

Returning to a view in a Tab Bar Controller Programatically

I have a TabBarController with 5 ViewControllers within it, on one of the ViewControllers, I have a set of buttons which load different view controllers outside of the TabBarController. These are loaded though the Modal Segue's, however the issue I am having is when I try to go back to the View within the Tab Bar it loads but without the Tab Bar itself, the code I have is:
class GreetingsVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goBack(sender: AnyObject) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("anonScreen") as! AnonVC
self.presentViewController(nextViewController, animated:true, completion:nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
How can I make it so when the back button is pressed it presents the View Controller from the Tab Bar Controller?
From my understanding, from the tabbar controller, you have present the GreetingsVC using presentViewController and you want to go back to previous view (one of the tabbar view controllers)
Instead of using presentViewController, you need to use dismissViewControllerAnimated
#IBAction func goBack(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}

How can view controller present it's self?

I have the following class below. The idea is it will use a custom Progress Window View Controller to handle progress of various different events. The problem is since this is in a class and not a view controller it's self, I'm not sure how to make the progressWindow actually show up after I instantiate it from the storyboard?
How do I do this? Currently I get an error that the application tried to present model view controller on itself.
import Foundation
import UIKit
class StatusProgress{
static var cancelCode = {}
static var runCode = {}
static var theProgressWindowController = ProgressWindowViewController()
static var returningViewControllerIdentifier = ""
static let storyboard = UIStoryboard(name: "Main", bundle: nil)
static func run(){
// This will run in parralel but on main queue. Has to be on this Queue because it might involve UI
dispatch_async(dispatch_get_main_queue(), {
// Update the UI on the main thread.
StatusProgress.runCode()
});
}
static func cancel(){
dispatch_async(dispatch_get_main_queue(), {
StatusProgress.cancelCode()
dispatch_sync(dispatch_get_main_queue(),{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier(returningViewControllerIdentifier)
vc.presentViewController(vc, animated: true, completion: nil)
})
});
}
static func show(){
dispatch_async(dispatch_get_main_queue(),{
theProgressWindowController = self.storyboard.instantiateViewControllerWithIdentifier("progressWindow") as! ProgressWindowViewController
theProgressWindowController.presentViewController(theProgressWindowController, animated: true, completion: nil) //use own instance to show it's self? (throws error! application tried to present modal view controller on itself. Presenting controller is <Inventory_Counter.ProgressWindowViewController: 0x1466ea390>.')
})
}
}
My problem is essentially I need a replacement for this line of code.
theProgressWindowController.presentViewController(theProgressWindowController, animated: true, completion: nil)
I forgot to mention here is the code that runs it inside another view controller.
SyncViewController.swift
import UIKit
class SyncViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func yesSyncButtonAction(sender: UIButton) {
StatusProgress.returningViewControllerIdentifier = "syncWindow"
StatusProgress.runCode = {
print("run code test")
}
StatusProgress.cancelCode = {
print("cancel code test")
}
StatusProgress.show()
}
#IBAction func noSyncActionButton(sender: UIButton) {
tabBarController?.selectedIndex = 1 //assume back to inventory section
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
The biggest problem is that your StatusProgress class is instantiating and showing a view controller. View controllers should instantiate and show other view controllers, model objects should not. So you need to move the logic for presenting the new view controller into you SyncViewController. Then use delegation to communicate to the SyncViewController that the syncing is done.
protocol StatusProgressDelegate {
func statusProgress(status: StatusProgress, shouldShow: Bool)
func statusProgress(status: StatusProgress, shouldCancel: Bool)
}
Your StatusProgress object would have a delegate that conforms to that protocol and call that delegate inside of its show and cancel methods. This means that you need to make the static functions instance methods, and write an initializer for the class so you can instantiate it.
If the view life cycle events are not much important for you, you may just add the view of your progress controller to view of your current controller. or it's even better if you supply the UIView parameter in your show() function.
static func show(attachToView: UIView ){
dispatch_async(dispatch_get_main_queue(),{
theProgressWindowController = self.storyboard.instantiateViewControllerWithIdentifier("progressWindow") as! ProgressWindowViewController
attachToView.addSubview(theProgressWindowController.view)
})
}
After all you'd better to remove your progress view from superview
static func cancel(){
dispatch_async(dispatch_get_main_queue(),{
theProgressWindowController = self.storyboard.instantiateViewControllerWithIdentifier("progressWindow") as! ProgressWindowViewController
theProgressWindowController.view.removeFromSuperview()
})
}

iOS Storyboard: Not able to instantiate view controller properly

I'm really having trouble instantiating a custom view controller.
This is my storyboard set up. The third view controller is the one I'm trying to present.
I've tried both of these methods.
1: This results in black screen.
var searchController: SearchController = SearchController()
self.presentViewController(searchController, animated: true, completion: nil)
2: This results in a white, empty view controller popping up.
let mainStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let searchController : UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("searchController") as! UIViewController
self.presentViewController(searchController, animated: true, completion: nil)
Here is the code for the actual view controller:
class SearchController: UIViewController {
lazy var searchBar: UISearchBar = UISearchBar(frame: CGRectMake(0, 0, 200, 20))
override func viewDidLoad() {
super.viewDidLoad()
var leftItem = (UIBarButtonItem)(customView: searchBar)
self.title = "Search"
self.navigationItem.leftBarButtonItem = leftItem
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
It's very confusing because another custom view controller I am is presented properly while using method #1 above. Why wouldn't it work for this controller?
Thanks a lot everyone.
When using Storyboards you don't need to use presentViewController or instantiate your view controllers manually. Instead it's best to use a segue to move from one UIViewController to the next.
1. In your case, you want a show segue, which it looks like you've already done judging by your storyboard.
2. You need to give your segue an Identifier which you can do by selecting your segue and going to the Attributes Editor.
3. To perform your segue just call the following from your first view controller (instead of presentViewController).
self.performSegueWithIdentifier("YourIdHere", sender: self)
This will cause the storyboard to instantiate your SearchViewController and present it in the way that you've defined for that segue.
4. If you want to pass any values to your SearchViewController, you can override prepareForSegue in UIViewController. In your first view controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let searchViewController = segue.destinationViewController where segue.identifier == "YourIdHere") {
// Now you can set variables you have access to in `searchViewController`.
}
}
And that should be it!

Resources