Swift: create programmatically UIViewController from xib - ios

I'm approaching to swift in this days and I've a question.
What if I have to create programmatically a new UIViewController?
Easy with an empty/new view controller:
var controller: UIViewController = UIViewController()
controller.view.backgroundColor = UIColor.whiteColor()
self.presentViewController(controller, animated: true, completion: nil)
Now, I have a xib file that I would like to load on the controller:
var controller: UIViewController = UIViewController(nibName: "FeedDetail", bundle: nil)
controller.view.backgroundColor = UIColor.whiteColor()
self.presentViewController(controller, animated: true, completion: nil)
This crash because:
'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "FeedDetail" nib but the view outlet was not set.'
I've already read this post and I can't understand what's wrong!

Sry I taken the answer from here, you missed something like (You have no view in xib so add one and then do this):
if you are using Xib follow this
follo following steps
1) open your xib file then right click on files owner and drag to your first view
2) then bind that view with outlet of "view"
hope you will get it...

Related

Swift: Cannot modify images in popup

Beginner swift-user here. I want to open a pop up connected to a seperate view controller (P2_Gift_Pop_Up) from the main view controller. To this end I include the following in a code snippet in my main view controller
let vc = P2_Gift_Pop_Up()
vc.modalPresentationStyle = .overCurrentContext
present(vc, animated: true, completion: nil)
This starts running code in the popup window (a print statement works anyway), so so far, so good.
However, when I try to modify some elements in the view connected to the view controller I get a
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value. Here is the code in its entirety.
import UIKit
class P2_Gift_Pop_Up: UIViewController {
#IBOutlet weak var Slot1: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
Slot1.setImage(UIImage(named: "Card 2 Red"), for: .normal)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Although I have (via another answer on this site) an understanding of what the msg means, I don't understand why I get it in this context, and how to fix it. It might also bear emphasis that although code starts running after the P2_Gift_Pop_Up call, the corresponding view is not shown.
You need to present your controller like this(you need to set your storyboard ID and then add this in identifier):
let storyBoard = UIStoryboard(name: "main", bundle: Bundle.main)
let vc = storyBoard.instantiateViewController(withIdentifier: "your storyboard id") as! P2_Gift_Pop_Up
vc.modalPresentationStyle = .overCurrentContext
present(vc, animated: true, completion: nil)
Your app is crashing because of your button(Slot1) not have a memory so you need to present like above.
#JogendarChoudhary told you what to do, but didn't really explain why.
When you create your P2_Gift_Pop_Up with
let vc = P2_Gift_Pop_Up()
You aren't initializing it properly. It doesn't get a chance to load it's views from it's XIB file/storyboard.
Assuming you have your view controller defined in your main app storyboard, you need to load the view controller from the storyboard.
You should add a unique identifier to your view controller in your storyboard, and then load it using that identifier. (Using the name of the class as the identifier is as good a choice as any.)
The UIViewController class has a property storyboard which will contain the storyboard from which it's loaded. Usually that's your app's main storyboard, and what you want. Thus:
if let vc = storyboard?.instantiateViewController(withIdentifier: "P2_Gift_Pop_Up id")
as? P2_Gift_Pop_Up {
vc.modalPresentationStyle = .overCurrentContext
present(vc, animated: true, completion: nil)
} else {
print("error creating P2_Gift_Pop_Up")
}

How to Open Multiple Xibs with the same method?

I have configured my UIView using Nib's .So, I just want to pass the name of nib in a method and it will open the particular ViewController.
For opening a particular UIView made with Xib, I have done it like this
func presentMyViewControllerNib(){
let controller = MyViewController(nibName: "MyViewController", bundle: nil)
let navigationController = UINavigationController(rootViewController: controller)
let currentController = getCurrentViewController()
currentController!.present(navigationController, animated: false, completion: nil)
getCurrentViewController here is just fetching the viewcontroller displayed.
So, i just want a method like this func presentGeneralisedNib(nibName:String) in which I pass the name of my Xib.
I think it's not possible but if someone can help.

Swift 3 - loading multiple ViewControllers at launch

I am working on making a tabbed app. It has a TabBarController and 4 ViewControllers attached to it.
By default, at launch only FirstViewController is loaded. I would like to load both FirstViewController and SecondViewController at start before switching to the second view via tab menu.
What i tried so far is that I created custom MyTabBarController class and tried to use
var sv = SecondViewController()
sv.loadView()
in ViewDidLoad(), but it caused a fatal error during loading, because (my guess) mapView element from storyboard was not loaded.
What is the correct way to simultaneously load the two viewControllers which use storyboard elements? All my other tries have not been successful so far.
Add in your main view controller
var secondViewController:UIViewController!
And in your viewDidLoad:
secondViewController: UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourIdentifier") as! SecondViewController
That's it. When you want to present it, use:
self.present(secondViewController, animated: true, completion: nil)

Programatically creating Segues in ios swift

In my app I use side bar as in facebook. when the user slides out the side bar a uiimageview is displayed. when user taps on the image it takes hm to a different viewcontroller. the problem i am facing is that I have created sidebar programatically and the other view to which I want to navigate the user is created using storyboard. So my source view is created programatically and destination view is created using storyboard. So can someone explain me if there is any way of using "Segue" in this scenario. Since i can not create segue using storyboard I need to do it programatically but even after a lot of googling i could not find the answer.
Well, to get another instance of another storyboard programmatically you can use something like:
let newController = UIStoryboard(name: "MyStoryboard", bundle: nil).instantiateViewControllerWithIdentifier("MyIdentifier") as! MyViewController
and then you push to your navigation controller, or add as a child view controller or something...
If you don't wanna bother with identifiers you can just use the instantiateInitialViewController instead of instantiateViewControllerWithIdentifier
Might help
"userSB" is the viewcontroller storyboard identifier
#IBAction func tapSearchCriteria(_ sender: Any?) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let aVC = storyboard.instantiateViewController(withIdentifier: "userSB") as? AViewController
aVC?.modalPresentationStyle = UIModalPresentationStyle.custom
aVC?.transitioningDelegate = self
aVC?.udelegate = self
self.present(aVC!, animated: true, completion: nil)
}

Splash Screen (Welcome) before Tab View

I'm trying to program an iOS App in Swift, where there would be a splash screen before the tab bar screen.
I've looked at:
http://sweettutos.com/2014/01/08/present-a-login-screen-before-the-tab-bar-controller-in-a-uitabbarcontroller-based-app/
Loading a Welcome Screen (Splash Screen) before TabBarController
but both of them require a nib file and I did all my UI in storyboard.
Here's my main question:
The code on the website has something like this:
ControllerName(nibName: "NibName", bundle: nil);
Is there any way I could do the same thing without the nib file and use storyboard?
Assuming that you have the TabBarController already in storyboard, you would add another view controller next to it.
Then you would click on the new view, and in the attributes inspector, check off "Is initial View Controller".
That makes that new view the first thing that comes up when the app is opened. To go to the tabBarController, I would probably have some button on that first view that just has a segue(control drag) to the TabBarController.
What you can do is the following the example in which the tab bar view controller is set as initial viewcontroller you can
Drag and drop another UIViewController from the Object Library into the storyboard object library.
Click on the UIViewController and assign it a StoryboardID
StoryboardID.
In your first view controller class you can access the storyboard and create an instance of the new view controller, that you dragged and dropped before, using the storyboard id, you can do it this in the viewDidAppear override function and present the new view controller modally.
override func viewDidAppear(animated: Bool) {
let myStoryboard = self.storyboard
let modalViewController = myStoryboard?.instantiateViewControllerWithIdentifier("ModalViewControlllerID")
presentViewController(modalViewController!, animated: true, completion: nil)
}
To instantiate programmatically a viewController from a storyboard in a similar way as you would do from a xib with ControllerName(nibName: "NibName", bundle: nil), it's:
UIStoryboard(name: "StoryboardName", bundle: nil)
.instantiateViewController(withIdentifier: "ControllerName")
But you must not forget to set the arbitrary identifier of your viewController in the storyboard under Storyboard ID:
Drag navigationController and viewController to storyboard and make navigationcontroller as initial viewcontroller then push tabbarcontroller from viewcontroller.
Thanks,
Nada Gamal
I just needed to do the same for my project. Here is my solution.
I created a ViewController and made it the Storyboard Entry Point in the Main.storyboard. I previously had a TabViewController with all kinds of setup and needed only 1 change there.
TabBarController should have a StoryboardID, I named my "TabBarID".
I created a new LaunchViewController swift file with that new ViewController added to my Main.storyboard and assigned it in Main.storyboard.
Here is that class. Very simple with a timer that once over the threshold will then present the TabBarViewController in fullscreen.
class LaunchViewController: UIViewController {
var timer = Timer()
var time = 0
var threshold = 2
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundTheme(theme: .orangeWhite)
Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true)
}
#objc func updateTimer() {
time += 1
if time > threshold {
timer.invalidate()
guard let storyboard = self.storyboard else {
//failed to find storyboard
return
}
let tabBarController = storyboard.instantiateViewController(identifier: "TabBarID")
tabBarController.modalPresentationStyle = .fullScreen
present(tabBarController, animated: true, completion: nil)
}
}
}

Resources