I started an app with a single view controller. I've since added a tab controller view and created 4 views that are setup as tabs, and that all seems ok.
The only viewcontroller.swift file I have is the original one. I'm not sure how to access the view controllers for each of the individual tabs.
Should I just use the one viewcontroller.swift for all my code and link the controls in each tab back to it?
To access the other view controllers, create classes of your UIViewController, like so. I'd recommend you put each class in a separate Swift file in your project, but it's not necessary.
class SecondViewController: UIViewController {
...
}
class ThirdViewController: UIViewController {
...
}
class FourthViewController: UIViewController {
...
}
Then assign them in the Identity Inspector by clicking each Storyboard UIViewController:
I make tabViewController just like this. Make my own viewcontrollers. First, init my own viewcontrollers. Then, push them into tabViewController.viewControllers
class TabbarController: UITabBarController {
override func viewDidLoad(){
super.viewDidLoad();
let first = YourFirstViewController();
let second = YourSecondViewController();
let thrid = YourThirdViewController();
self.viewControllers = [first, second, third];
}
}
Related
I have four ViewController, I don't use an UITabbedbar because It's more difficult to customize.
I use modal segue but I think the memory consumption is excessive.
this is a screen shot of my first and second VC.
What I have to use to change View correctly?
That's the code I use :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "second") {
let secondVC = segue.destinationViewController as SecondViewController;
}
}
From your Storyboard diagram, it is clear that you have created a segue from each button in your "tab bar" to another view controller. Except for the unwind segue, segues always create a new instance of the view controller they are switching to. So if you use your setup to switch from view controller 1 to view controller 2 and then back to view controller 1, you won't be returning to the view controller you came from but instead you will be creating an entirely new view controller 1.
This is why your memory consumption is excessive. You keep creating view controllers until your app crashes.
I would recommend you return to using a tab bar controller. They were designed to allocate the view controllers once up front and then just switch between them. Also, they have a standard look for a reason, it helps the user of your app know immediately how to interact with them.
To pass data between tabs, you won't use segues because there is no segue happening when you switch tabs. There are many ways you can do this, but they all boil down to having model data stored where all of the tabs can access it. This can be done with CoreData in a larger app. For a simple app, you can do the following:
Create a custom subclass of UITabBarController. Let's call it CustomTabBarController. Have that class create and hold the model data that will be accessed by each of your tabs.
CustomTabBarController.swift:
import UIKit
// This class holds the data for my model.
class ModelData {
var name = "Fred"
var age = 50
}
class CustomTabBarController: UITabBarController {
// Instantiate the one copy of the model data that will be accessed
// by all of the tabs.
var model = ModelData()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
In your Storyboard, in the Identity Inspector, change the class of UITabBarController to CustomTabBarController.
In viewWillAppear in each of your tabs, get a reference to the model data and then you can use it.
FirstViewController.swift:
import UIKit
class FirstViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get a reference to the model data from the custom tab bar controller.
let model = (self.tabBarController as! CustomTabBarController).model
// Show that we can access and update the model data from the first tab.
// Let's just increase the age each time this tab appears and assign
// a random name.
model.age += 1
let names = ["Larry", "Curly", "Moe"]
model.name = names[Int(arc4random_uniform(UInt32(names.count)))]
}
}
SecondViewController.swift:
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var ageLabel: UILabel!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get a reference to the model data from the custom tab bar controller.
let model = (self.tabBarController as! CustomTabBarController).model
// This tab will simply access the data and display it when the view
// appears.
nameLabel.text = model.name
ageLabel.text = "\(model.age)"
}
}
I am taking reference from tutorial here.
I have one View Controller which contains a Container View. On this Container View I have added Custom Segue i.e. FirstViewController. That means when I opens View Controller it by default shows FirstViewController. And on FirstViewController, I have a Button. And by clicking on this button I want to show SecondViewController but I am not able to get this achieved. I have also added print command on Button click and it prints on console and not switch to another View. Please help.
I have created a delegate in FirstViewController and aa function which reference through ViewController.
Code for FirstViewController.swift
protocol FirstViewDelegate: class {
func sendToSecondViewController()
}
class FirstViewController: UIViewController {
weak var delegate: FirstViewDelegate? = nil
#IBAction func goToSecond(_ sender: UIButton) {
print("test1")
delegate?.sendToSecondViewController()
}
}
Code for ViewController.swift
extension ViewController: FirstViewDelegate{
func sendToSecondViewController() {
container.segueIdentifierReceivedFromParent("second")
}
}
And main.storyboard
Seems you have not set delegate of FirstViewController in ViewController. Something like:
<object of FirstViewController>.delegate = self (Inside ViewController)
I need a settings screen in my app which I intend to create with a simple static table view. Unfortunately I ran into an issue. When I assign a custom view controller to the view in my storyboard the views table goes black during runtime.
This is despite the view controller not changing the default behaviour. I only override one method at this point, to put the Settings string in the title.
import Foundation
import UIKit
class SettingsViewController: UITableViewController {
override func loadView() {
self.title = "Settings"
}
}
When I remove the custom view controller the table appears normally.
I segue into the view using the following code.
guard let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewController(withIdentifier: "settingsViewController") as? UITableViewController else { // or SettingsViewcontroller for the first version
print("Could not instantiate view controller with identifier of type SettingsViewController")
return
}
self.navigationController?.pushViewController(vc, animated:true)
What could cause this issue?
You have to call super.loadView(), You are overriding the UITableViewController's loadView() and not calling the super class method, Due to that you are getting black screen.
import Foundation
import UIKit
class SettingsViewController: UITableViewController {
override func loadView() {
self.title = "Settings"
super.loadView()
}
}
I have a UIViewController-class instantiated via Storyboard that contains a constant property. For testing, I want to replace/mock whatever the value of the view controller.
I can actually do this by subclassing and defining a new constant and by overriding the methods that use it. However, I do not know how to instantiate the ViewController, since it's not in the storyboard.
It's important that all views and all other functionality of the original ViewController is still present, of course. How to go about it?
If i understand you need to access a property from another ViewController outside your Storyboard without presenting it. Since you're using swift, all you need to do is instantiate the class itself i believe. For example if the ViewController that is not in the storyboard has a class named "SecondController", and the variable inside second controller is called "stringVar" then all you need to do is this:
var secondVC = SecondController()
secondVC.stringVar = "new string value"
Example:
//SecondVC
import UIKit
class SecondViewController: UIViewController {
var something:String! = "String Value";
}
//Main VC
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var secondVC = SecondViewController()
secondVC.something = "Another String Value"
println(secondVC.something)
}
}
I have four ViewController, I don't use an UITabbedbar because It's more difficult to customize.
I use modal segue but I think the memory consumption is excessive.
this is a screen shot of my first and second VC.
What I have to use to change View correctly?
That's the code I use :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "second") {
let secondVC = segue.destinationViewController as SecondViewController;
}
}
From your Storyboard diagram, it is clear that you have created a segue from each button in your "tab bar" to another view controller. Except for the unwind segue, segues always create a new instance of the view controller they are switching to. So if you use your setup to switch from view controller 1 to view controller 2 and then back to view controller 1, you won't be returning to the view controller you came from but instead you will be creating an entirely new view controller 1.
This is why your memory consumption is excessive. You keep creating view controllers until your app crashes.
I would recommend you return to using a tab bar controller. They were designed to allocate the view controllers once up front and then just switch between them. Also, they have a standard look for a reason, it helps the user of your app know immediately how to interact with them.
To pass data between tabs, you won't use segues because there is no segue happening when you switch tabs. There are many ways you can do this, but they all boil down to having model data stored where all of the tabs can access it. This can be done with CoreData in a larger app. For a simple app, you can do the following:
Create a custom subclass of UITabBarController. Let's call it CustomTabBarController. Have that class create and hold the model data that will be accessed by each of your tabs.
CustomTabBarController.swift:
import UIKit
// This class holds the data for my model.
class ModelData {
var name = "Fred"
var age = 50
}
class CustomTabBarController: UITabBarController {
// Instantiate the one copy of the model data that will be accessed
// by all of the tabs.
var model = ModelData()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
In your Storyboard, in the Identity Inspector, change the class of UITabBarController to CustomTabBarController.
In viewWillAppear in each of your tabs, get a reference to the model data and then you can use it.
FirstViewController.swift:
import UIKit
class FirstViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get a reference to the model data from the custom tab bar controller.
let model = (self.tabBarController as! CustomTabBarController).model
// Show that we can access and update the model data from the first tab.
// Let's just increase the age each time this tab appears and assign
// a random name.
model.age += 1
let names = ["Larry", "Curly", "Moe"]
model.name = names[Int(arc4random_uniform(UInt32(names.count)))]
}
}
SecondViewController.swift:
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var ageLabel: UILabel!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get a reference to the model data from the custom tab bar controller.
let model = (self.tabBarController as! CustomTabBarController).model
// This tab will simply access the data and display it when the view
// appears.
nameLabel.text = model.name
ageLabel.text = "\(model.age)"
}
}