UIPageViewController wont refresh UITableViewControllers - swift

Have a controller, we'll call it Bob, as a modal and it contains some labels and a UIPageViewController that loads 2 table controllers. The first time the page controller loads it loads the table controllers with all the correct data. Whenever Bob is opened again the table controllers data does not change. Bob's labels do change so it is receiving different requests from it's parent.
pageController is the name of the UIPageViewController
I've tried doing the following in the datasource section for the pageController
pageController.dataSource = nil
pageController.dataSource = self
but it didn't work. I've also tried setting the controller again after the new data is loaded and that didn't work either
pageController.setViewControllers([viewController(At: 0)!], direction: .forward, animated: true, completion: nil)
In the table controllers they are set to refresh their data like so and this is called after the new data is passed to them. I've verified that this is called whenever Bob is opened.
DispatchQueue.main.async(execute: { () -> Void in
self.tableView.reloadData()
})
I've also tried recreating the UIPageViewController altogether and that didn't work either.
I'm really stumped as to how to get the page controller to reload the table controllers with the new data. I don't think the issue is at the table controllers but I'm open to trying anything. Anyone have any ideas?

So the cause wasn't any of what I had listed. Go figure. Instead it was how I was defining the table controllers. I was setting the value they where to use for loading when I was defining the controller and not at the time of when I load it.
So
private lazy var thatTableViewController: ThatTableViewController = {
let storyboard = UIStoryboard(name: "ModalsStoryBoard", bundle: Bundle.main)
var viewController = storyboard.instantiateViewController(withIdentifier: "ThatTableViewController") as! ThatTableViewController
viewController.view.tag = 0
return viewController
}()
used to also have a line like so
viewController.controller = Controller(id: self.markerId, activeController: .Problem)
Controller is a custom struct that I was passing. But by setting this at the same level as where the variable thatTableViewController is defined it would not change between calls since it was cached. So moving the
viewController.controller = Controller(id: self.markerId, activeController: .Problem)
outside the definition part, allowed it get changed and not cached.
This then allowed me to remove
pageController.dataSource = nil
pageController.dataSource = self
since the data is defined at the time that I get the controller that I want to load and not predefined.
Hopefully, this will help someone else to not do the same thing I did and set any values you need the other controllers to use to be defined not when you define the controller but later on when you need to use the controller.

Related

Passing information from one storyboard to another

I am having trouble passing the score to quiz app from a model page to one of my controllers. I have a counter that totals up the score, however when I try and add it to a label on another storyboard it takes the original declared value of zero rather than the updated version.
This is where the function of counting is taking place and im just activating the function on another storyboard
Obviously, it will give you zero because there is no update in score variable.
One way to pass score from one view controller to other view controller is as:
create a variable in destination view controller
Initiate destination view controller from current controller.
Assign current score to destination view controller's variable before pushing or presenting it.
In viewdidload or wherever you want to display it, assign score to its label
Here is sample code you can do:
let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "myVCID")
vc.anyVariableYouDeclare = currentScore
self.present(vc, animated: true)

Swift iOS Dynamic Tab bar from json response

I'm new to iOS/Swift. My application is using a json data and I have to create tab bar using the json response. I mean, I get Array of Title from json and I have to create tab bar items based on that array. The Array data/count may change and the app should display the tab bar accordingly. I am trying to create the tab bar programatically without storyboards (as this is huge tab bar)
So far, I have tried the below code -
func tabBarCustom() {
let tt = UITabBarController()
var array1 = [UIViewController]()
var controller1 = UIViewController()
for i in 0..<navgTitle.count {
controller1 = UIViewController(nibName: "WeatherViewController", bundle: nil)
controller1.title = navgTitle[i]
controller1.tabBarItem = UITabBarItem(title: navgTitle[i], image: .none, tag: 1)
array1.append(controller1)
}
print(array1)
tt.viewControllers = array1
self.view.addSubview(tt.view)
}
The above code is failing saying - Could not load NIB in bundle: 'NSBundle' with name 'WeatherViewController'
I am not sure how to create multiple view controllers automatically using the title array, taking title as name of the view controller. is this possible? and how to loop in the array to create view controllers for each tab bar item
please help.Thank you
Are you using nibs? If so, your project can't find the nib file, and you should check out this: Could not load NIB in bundle: 'NSBundle'. Or are you using Storyboard? If you are trying to initialize from the storyboard, you'll do something like this:
let vc = sb.instantiateViewController(withIdentifier: "WeatherViewController")
(just be sure to add WeatherViewController as the view controller's identifier).
OR are you using code? If you are trying to create your view controller from code, you simply need to do WeatherViewController().
As for the tab bar, you're in the right direction it's just that creating the view controller is failing.

What is the simplest way to modify variable by using the Button for later use of that variable in another View Controller?

I have two view controllers. One VC with a button and a label and one VC only with a label. I created button action that can modify variable (declared in the class of that first viewcontroller) if the button is pressed and I can show that MODIFIED variable as the label in that same VC but my intent is to show that MODIFIED variable on another VC.
I want to use that button to go to the second VC where the modified variable should be displayed on the label when that VC is displayed. In first VC I declared:
var myVariable: String = "default"
In the button action:
{myVariable = "700"}
In second VC I declared:
let vc1: ViewController1 = ViewController1()
I assigned an action to the button in first VC (dragging to second VC to show the second VC) and in viewdidload of the second VC I try to acces the variable from first VC with:
label.text = vc1.myVariable and it accesses it but ...
...but the result is DECLARED/notMODIFIED state of variable. So if I show myVariable on same VC it is OK but on the second VC myVariable was not changed by the button action on the first VC.
I am trying to avoid delegation as it seems complicated..
What is the easiest way to accomplish task? Thank you guys.
To get updated value of first VC variable to second VC you can use NSNotificationCenter.
In first VC when you change value at that time you have to post notification with dictionary like following.
NotificationCenter.default.post(name: NSNotification.Name("ValueUpdate"), object: nil, userInfo: ["variable": myVariable])
For that you have to observe Notification in second VC
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification(notification:)), name: Notification.Name("ValueUpdate"), object: nil)
And then you have to implement following method to get update in your second VC
#objc func handleNotification(notification: Notification) {
label.text = notification.userInfo?["variable"]
}
The SIMPLEST way to do this is to define a global variable. So you can access it from anywhere. It should be define outside of anything to be global.
#import UIKit
var myGlobalVariable = "Initial value"
class MyClass { ... }
then you can change or read it from anywhere like print(myGlobalVariable).
Note that although it is the simplest solution, it is also THE WORST solution too. Global functions and variables use cases are vary rare.
Inject your data via initializer while showing controller.
show(SecondViewController(name: name), sender: nil)
Check out this code.
#Eljer...
Although Delegation seems VERY hard at first its very easy.
You need to remember 3 steps only as a beginner ! I'll try to make it easy for you to use here.
Step 1 : Create tempVariable (of same type) on second View controller also (you can make with same name also doesnt matter)
Step 2 : Write this code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let xyz = segue.destination as! abc
}
The xyz is the name you want to call it with.
The abc is the name of your second view controller where you made the other same type of variable.
What this will do is, it will make an object of EVERYTHING (that includes all variables and functions) that you have on your Second View controller available to you on your First view controller also.
To use / assign value to the label on second view controller what you need to do is...
just add :
xyz.yourVariableNameOnSecondViewController = variableNameOnFirstViewController
this will assign the value of your variable on First VC to the variable on Second VC also
Finally, to get the value updated. You need to get this updated value using viewDidLoad on your second view controller.
I hope this helps, if its still confusing ask me anything.
Gluck

How to pass map annotation on segue to mapView on another vc?

I currently have a map with annotation and would like to pass this to another map on another VC (replicate the map). How can I do this in my prepare for Segue function?
In my current map VC
if segue.identifier == "addEntrySegue",
let addEntryVC = segue.destination as? AddEntryViewController
{
addEntryVC.mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05,0.05)
let region = MKCoordinateRegionMake(annotation.coordinate, span)
addEntryVC.mapView.setRegion(region, animated: true)
}
The basic idea of passing data in prepare(for:sender:) is correct.
Obviously, you will want to make sure that the identifier and the cast of the view controller were successful, perhaps by adding a breakpoint inside that if statement. I would have thought that if this if statement was successful, that you would have crashed when you tried to interact with mapView at this point, so I wonder if this if statement is succeeding at all. If it isn't succeeding, you'll want to double check (a) the spelling and capitalization of the storyboard identifier that you specified for the segue in IB; and (b) that the base class of the destination scene is really AddEntryViewController.
But, even if you confirm that the if statement is working properly, you cannot just update UIKit controls of the destination view controller in prepare(for:sender:), because they haven't been created yet. Thus, you can't reference the map view in prepare(for:sender:).
You should have an annotation property in your AddEntryViewController, and the prepare should simply set that. Then, in viewDidLoad of AddEntryViewController, by which point the views have been created, add that annotation to the map view and set the region/camera.

How do I segueing to the UIViewController I'm in?

I'm trying to go from one view, filled with data from an object, to the same view but filled with a different object via segue.
Using a segue is necessary as apposed to switching the object and refreshing the view because my users need to be able to go back to the past view controller when they hit the back button.
Example:
(ThisView, with thisObject populating the view) -> (ThisView, with thisOtherObject populating the view)
What I've tried:
presentView Controller: This didn't work because it is not the default segue I'm trying to achieve.
let next: NewClubProfile = storyboard?.instantiateViewControllerWithIdentifier("clubProfile") as! NewClubProfile
presentViewController(next, animated: true, completion: nil)
Using Navigation Controller: Can't figure out how to segue the new object to populate the other view
let next: NewClubProfile = storyboard?.instantiateViewControllerWithIdentifier("clubProfile") as! NewClubProfile
self.navigationController?.pushViewController(next, animated:true)
Should have taken longer to solve this myself before posting this but I couldn't find an answer that fit what I needed. Anyway, solved it, here's what worked for me.
let next: ViewController = storyboard?.instantiateViewControllerWithIdentifier("viewName") as! ViewController
next.object = newObject
self.navigationController?.pushViewController(next, animated:true)