iOS Swift - Call function for another class and see null variables - ios

i have three classes, where i have a container, mainview and a left menu.
App looks like this
When i press a button in the left menu, this execute an action in mainview:
var viewController: ViewController = ViewController()
func menuLeftButton1(){
self.viewController.doActionInMainView()
}
But, when i want to change a variable of the mainview in that function in debuger says that the varieble of maninview is null.
I think that the variables of the mainview are destroyed and i can't use them when i return from the left menu.
Other case is when i have a switch in the left menu and I enable it
and close the left menu and open again the switch looks like I haven't
enable it.
Can u help me with this case? Thanks.

I think problem is in this code:
var viewController: ViewController = ViewController()
You need to instatiate viewcontroller from a xib or storyboard
For storyboard you can do this:
You need to set the identifier of the view controller in storyboard
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewControllerIdentifier")

Related

iOS Top Navigation Bar

Which is the best approach in order to create a Top Navigation Bar like this one on Instagram?
I have a Tab Bar controller which has 5 views but I do not understand how to create another navigation bar inside one of this views. Should I create two labels and connect each of them with another view or is there something better to achieve this?
Your approach is good, would be nice to see some screenshots or code to fully understand it.
If you want to put navigation bar inside those tab bar views you need to put a container view that connects to a navigation controller.
I created a simple project to show you how I achieved this.
Using a scrollview to contain another two view containers embedded with some navigation controllers:
The view containers allows you to embed any type of view / controller:
Apple docs has a nice reference of how to do this, in your case you just need to change ViewController to NavigationController.
And if you don't mind to use third party code, well there are plenty of options for you to choose:
PolioPager
import PolioPager
class ViewController: MainContainerViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func tabItems()-> [TabItem] {
return [TabItem(title: "One"),TabItem(title: "Two")]
}
override func viewControllers()-> [UIViewController]
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController1 = storyboard.instantiateViewController(withIdentifier: "cont1")
let viewController2 = storyboard.instantiateViewController(withIdentifier: "cont2")
return [viewController1, viewController2]
}
}
In above example you can use PolioPager to instantiate 2 different navigation view controllers, identified by storyboard identifier cont1 cont2 for example.
Other trip party libraries:
https://github.com/XuYanci/GLViewPagerController
https://github.com/rechsteiner/Parchment

Showing a view controller across the app

I am having one view controller which should be hide and show from everywhere in the app without initializing it again. So I just want to know that how can I achieve this. Like by adding that view controller as childView or by presenting it to navigation controller or anything else.
The idea is that the view controller can be shown or hide from any screen of the app.
You can make a view controller as a cocoa touch class... and you can add a xib to it.. once you design the interface for the view controller..
You can make a singleton class and keep the shared instance like this:
class YourViewController: UIViewController {
static let sharedInstance = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourStoryBoardId")
}
To show this just do :
func someFunc() {
show(YourViewController.sharedInstance, sender: self)
}
I once did something like this in one of my apps.. i think its a standard approach.
You could also see this for more info and source

childViewControllers is empty after calling addChildViewController

I have a question regarding add/remove childviewcontrollers with ContainerView.
I have a UIViewController named "ContainerViewController" that contains a ContainerView, and this ContainerView has a UIViewController named "ContainerLinkViewController". I also have four other UIViewControllers that will be added to or removed from this "ContainerLinkViewController" whenever user a clicks one of the tab button that is placed at the bottom of "ContainerViewController". The storyboard looks like below.
NOTE that the custom segues connected to those four UiViewcontrollers are just empty segue that does nothing but show visual connection in storyboard.
So what I do is first add the First Tab ViewController to "ContainerLinkViewController" as a childViewController by using below code in viewDidLoad().
let firstTabViewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstTabViewController") as! FirstTabViewController
self.addChildViewController(firstTabViewController)
firstTabViewController.view.frame = self.view.bounds
self.view.addSubview(firstTabViewController.view)
firstTabViewController.didMove(toParentViewController: self)
After this initial setup, whenever user tabs on one of those tab buttons, I send signal from "ContainerViewController" that which UIViewController is to be added as new childViewController to "ContainerLinkViewController" and switching the old childViewController and this new childViewController using the below code.
func swapViewControllers(from : UIViewController, to : UIViewController) {
from.willMove(toParentViewController: nil)
self.addChildViewController(to)
to.view.frame = self.view.bounds
self.transition(from: from, to: to, duration: 1.0, options: UIViewAnimationOptions.transitionCrossDissolve, animations: nil) {
finished in
from.view.removeFromSuperview()
from.removeFromParentViewController()
to.didMove(toParentViewController: self)
}
}
Before calling this "swaptViewControllers()", I take the old childViewController by doing the following.
let oldChildViewController = self.childViewControllers.last
My problem is that this "oldChildViewController" is nil when I click one of those tabs for the first time right after the initial setup. So the function "swaptViewControllers()" does not even called because the self.childViewControllers is empty.
I have been struggling with this for few days now and could not find clear answer to solve this. So I decided to ask here to get some help about what might cause this.
Any help?? Thanks.
NOTE : I am using swift 3. Maybe this would help to answer my question since it seems lots of things changed fro swift 2.

How to make dynamic uitabbar controllers?(swift)

I make an app that has 3 tabs. I want to make my tab bar controller dynamically change the view controller of the first tab bar according to the logged in user type. The rest two tab bars are static. For example, if the user type is 1, I want to show ViewController1 for the first tab, and if the user type is 2, I want to show ViewController2 instead. Is this impossible to achieve when the tab bar is designed in the storyboard? I use storyboard in the app.
You can change these by using the function on a tabview controller setviewcontrollers (see documentation here: https://developer.apple.com/documentation/uikit/uitabbarcontroller/1621177-setviewcontrollers).
For instance I have a storyboard with 4 Viewcontrollers in a tabviewcontroller, and then in the first viewController that loads, I added the following in viewDidLoad()"
let storyboard = UIStoryboard(name: "myStoryboard", bundle: nil)
let newTab = storyboard.instantiateViewController(withIdentifier: "testControllerID") as! TestViewController
let myControllers = [newTab, tabButton2, tabButton3, self, tabButton4]
tabBarController?.setViewControllers(myControllers, animated: true)
So I was able to rearrange my previously defined tabs as well as add "newTab", which is a VC designed on the storyboard, given an identifier, but not actually added to the tabViewController.
Hope that helps

Reusing UIViewController for two Tab bar items

I have 1 tab bar controller in storyboard and 1 UIViewController associated with it. I would like to re-use the same UIViewController in order to create second item in tab bar. When I am creating second relation from tab bar to view controller I need to specify 2 different items names. How can I re-use same view controller and set different items names from storyboard? If not possible to do it in storyboard, then do I have to rename each in tab bar controller class or there is better way?
I was going to provide different data to view controller in prepareforsegue.
UPDATE:
little more details and clarification
In above screenshot marked VC at the moment is reachable a) directly from tab, b) through 3 transitions. I want to add another DIRECT relation to initial tab bar, just like in case of "a".
I can give you a little tweak for that and at least that worked for me.
Drag a tabbarcontroller and associated tab item view controllers to
your storyboard. Name them as you like.
Create an extra view controller that you want to reuse from your storyboard.
Add container views to each tab item view controllers and remove their default embedded view controllers.
Create embed segue from each tab item controller to your re-usuable view controller.
The configuration looks something like the following:
Thus you can use the same embedded VC for different tabbar item. Obviously if you need the reference of the tabbarcontroller, you need to use self.parentViewController.tabBarController instead of self.tabBarController directly. But it solves the issue of reusing a VC right from the storyboard.
I've found much simpler solution using storyboard only.
Setup your storyboard like this:
Then in your Navigation Controller Identity Inspector set Restoration ID like this:
And in your ViewController class file put the following code:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = parent?.restorationIdentifier
label.text = parent?.restorationIdentifier
}
or do what you like based on parent?.restorationIdentifier value
If you don't want the Navigation TopBar to appear on the ViewController just set it to None in Attributes Inspector of the desired Navigation Controller like this:
That's it! Hope it helps.
Yes you can.
All you need to do is to create a new View Controller in StoryBoard as if there is going to be a different View Controller for tab 2. Then Select the 2nd view controller and simply add its class name the same classname of view controller 1
Things to note:
When you are sharing the same view controller class (.m ad .h) files, each tab will create a NEW instance of that class.
Edit:
This works as long as you have either a "custom" cell scenario (i.e. reusing two table view controllers) OR, have all your views inside a "container view" (i.e. reusing UIView).
I needed slightly different solution than the accepted answer. I needed to use same Table View Controller with the different data source for different tab bar items. So in the storyboard, i created two Navigation Controllers with same classes like this;
I also give different "Restoration ID" to each of them.
For the first one, I gave "navCont1" and "navCont2" for the second one.
In subclass("GeneralNavCont") of these Navigation Controllers; I override init method and check restoration id of self. Then i initiate my TableViewController and set its data source based on ids like this;
class GeneralNavCont: UINavigationController {
var dataSource1 = [Countries]()
var dataSource2 = [Cities]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initiateTableVCBasedOnId()
}
func initiateTableVCBasedOnId() {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let tableVC = storyBoard.instantiateViewController(withIdentifier: "tableVC") as! MyTableViewController
if self.restorationIdentifier == "navCont1" {
tableVC.dataSource = self.dataSource1
self.viewControllers = [tableVC]
}
else if self.restorationIdentifier == "navCont2" {
tableVC.dataSource = self.dataSource2
self.viewControllers = [tableVC]
}
}
}
Hope it helps someone. Cheers.

Resources