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()
}
}
Related
Is there a way to reposition the UIKit tab bar vertically? Like the
gmail app navigation
This question has been asked quite a few times. None of the solutions I found seem to work for me. I’m looking for a solution from scratch in Swift, no third party libs.
Just like what #rmaddy has commented, you will need to create a customised tab and place it in a view as shown below.
FYI, you can easily build a customised tab bar by using buttons.
Once clicked, you just need to add the new controller as a subview by using the extension below.
extension UIViewController {
func add(parentViewController: UIView, childViewController: UIViewController) {
// Add Child View Controller
addChild(childViewController)
// Add Child View as Subview
parentViewController.addSubview(childViewController.view)
// Configure Child View
childViewController.view.frame = parentViewController.bounds
// Notify Child View Controller
childViewController.didMove(toParent: self)
}
}
So from your main view controller, it should look something like this.
class MainController: UIViewController {
// Outlets
#IBOutlet weak var mainView: UIView!
// Lazy loaded controller
private lazy var tab1Controller: Tab1Controller = {
// Instantiate View Controller
let tab1Controller = UIStoryboard(name: "Tab1Controller", bundle: nil).instantiateViewController(withIdentifier: "Tab1") as! Tab1Controller
return tab1Controller
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
// MARK: - Tab Bar
#IBAction func Tab1TouchUpInside(_ sender: Any) {
// Navigate to child view
self.add(parentViewController: self.mainView, childViewController: self.tab1Controller)
}
}
Hope it helps!
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 have a HomeView class with scrollView IBOutlet and a function the changes the offset of the scrollView:
scrollView.setContentOffset(CGPoint(x: self.view.frame.width * 2, y: 0), animated: true)
From the FeedView class I attempt:
let Home = HomeView()
Home.ScrollRight()
But I get this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Because your HomeView created by either XIB or Story board. Thats why below line return nil object.
let Home = HomeView()
If you want to call ScrollRight() method of HomeView from another class then declare global variable of HomeView like
var homeVC = HomeView()
and in viewDidMethod of HomeView
homeVC = self as HomeView
not you can access homeVC from anywhere
and just call method by
homeVC.ScrollRight()
from another viewController.
=======================================
EX
import UIKit
var homeVC = HomeVC()
class HomeVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
homeVC = self as HomeVC
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Now you can use homeVC object and access property of HomeVC anywhere.
NOTE:
If you are calling function from same viewController (HomeView) then you don't need to create object of that viewController. You can just simply call function by below like directly.
ScrollRight() OR self.ScrollRight()
If your scroll view is set up as an outlet it means it is created within your view controller's main view when said view controller is instantiated from a storyboard.
This code:
let Home = HomeView()
...at most instantiates the view controller itself, but it does not load its view (let alone wire the outlets to the appropriate subviews -in this case, your scroll view).
Please read about view controller view life cycle. It's all in Apple's programming guides and countless tutorials online.
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];
}
}
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)"
}
}