Create instance of viewcontroller without presenting it in Swift - ios

I have a tabViewController with two view controllers, a map and a UIListView. I want to pass the current map region center to the listView controller but currently that requires the user to tap the UIListView controller first, then go back to the map, and then back to the listview controller in order for the map region center value to be passed.
Im sure there is a simple and elegant way of solving this, I'm just not sure how.

Why don't you create a singleton that gets updated by some view controllers and read by others? That would be the preferred way to let two otherwise unrelated view controllers communicate, even when not allocated at the same time.
Edit
Suppose you have a class like this:
class PointSingleton {
var point = CGPointZero
static let sharedPoint : PointSingleton = PointSingleton()
private init() {}
}
You now can
PointSingleton.sharedPoint.point = CGPoint(x: 2, y: 3)
as well as use
PointSingleton.sharedPoint.point
wherever you like.

On tap of UIListView item change the selected index of the Tab Bar Controller. Without any code provided, the best I can provide is
tabBarController?.selectedIndex = 0;
then to pass data
var destinationViewController = tabBarController.viewControllers[0] as UIViewController
destinationViewController.whateverVar = "some value"
EDITED:
on your list view create a way to access your MapViewController
//your map
var mapVC = tabBarController.viewControllers[0] as UIViewController
then grab the map center like you normally would
var centerCoord = mapVC.mapView.centerCoordinate

Related

swift; xcode 9.2 - Passing arguments over TabBar & navigation controller

In my storyboard I got:
UIView -> UITabBarController -> UINavigationController -> UITableView
Now I want to pass an object from UIView into UITableview. I do get the object to the TabBarController from the prepare for segue func, but from there I kind of get lost.
How to identify what segue you have on the itemlist from the TabBarController?
Could somebody give some example code for the UITabBar and Navigation controller to pass the data?
Phillip is right.
You can do it as following:
class Model {
static let shared = Model()
var data: String // or anything else
}
in UIView:
Model.shared.data = "some data"
in UITableView
let data = Model.shared.data
//do smth with data...
Anton is suggesting the Singleton pattern. It is important to understand what it is when you decide to use it has both its benefits and potential pitfalls. https://thatthinginswift.com/singletons/ is a place to start reading up.
There are ways to just pass an object from one view to the other and that is useful knowledge to know. Both TabBarVC's and NavigationVC's have their viewControllers property which allows you to access an array of their child vc's. You can use this to pass information to specific child vc's. Depending on your needs this may be more appropriate than creating a singleton.
For example:
let childVC = tabBarVC.viewControllers[0] as! MyCustomVCClass
childVC.inheretedObject = objectIWantToSend
This would pass an object to the vc that ocupies the first tab of a tab bar vc.

Detect that from which Page I come to the current Page

I want to know how to do this:
I have 3 view controllers and the first and second view controller are connected to the third one !
I want to know how can I write a code that detect from which one I came to this view controller
I have searched here for my answer But all of the similar questions asked about navigation !!!
The Important thing is that I don't have navigation in my app!!
I don't know if my answer will help you in your specific case, but here is the implementation I see from what you are asking. Maybe it will inspire you.
So imagine your are in your homePage or whatever viewController and you want to navigate throw other, but you want to know from which viewController you came from.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:segue_VC1]) {
CustomViewController1* destinationVC = segue.destinationViewController;
destinationVC.fromSegue = #"I AM VC 1";
}
if ([segue.identifier isEqualToString:segue_VC2]) {
CustomViewController2* destinationVC = segue.destinationViewController;
destinationVC.fromSegue = #"I AM VC 2";
}
}
The more important thing you have to know is that you can access attribute from the destination view controller you will access with your segue.
I know this is in Obj C, but the implementation is still the same.
So that when you navigate from a ViewController to an other one, you can set the attribute of the destinationViewController.
Then when you are in the view controller you wanted to navigate you can check :
if ([_fromSegue isEqualToString: "I AM VC 1"])
// do specific stuff when you come from VC 1
else if ([_fromSegue isEqualToString: "I AM VC 2"])
// do specific stuff when you come from VC 2
else
// other case
There are many ways to do that like simply passing a view controller as a property to the new instance. But in your case it might make more sense to create a static variable which holds the stack of the view controllers the same way the navigation controller does that.
If you are doing this only between the UIViewController subclasses I suggest you to create another subclass of it form which all other view controllers inherit. Let us call it TrackedViewController.
class TrackedViewController : UIViewController {
static var currentViewController: TrackedViewController?
static var previousViewController: TrackedViewController?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
TrackedViewController.previousViewController = TrackedViewController.currentViewController
TrackedViewController.currentViewController = self
}
}
Now you need to change all the view controllers you want to track so that they all inherit from TrackedViewController as class MyViewController : TrackedViewController {. And that is pretty much it. Now at any point anywhere in your project you can find your current view controller via TrackedViewController.currentViewController and the previous view controller via TrackedViewController.previousViewController. So you can say something like:
if let myController = TrackedViewController.previousViewController as? MyViewController {
// Code here if the screen was reached from MyViewController instance
}
Now the way I did it was through the instance of the view controller which may have some side effects.
The biggest problem you may have is that the previous controller is being retained along with the current view controller. That means you may have 2 controllers in memory you do not need.
If you go from controller A to B to C and back to B then the previous view controller is C, not A. This might be desired result or not.
The system will ignore all other view controllers. So if you use one that is not a subclass of TrackedViewController the call will be ignored: A to B to UITableViewController to C will report that the C was presented by B even though there was another screen in between. Again this might be expected result.
So if the point 2 and 3 are good to you then you should only decide weather to fix the point 1. You may use weak to remove the retaining on the two properties but then you lose the information of the previous view controller if the controller is deallocated. So another choice is to use some identifiers:
class TrackedViewController : UIViewController {
static var currentViewControllerID: String?
static var previousViewControllerID: String?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
TrackedViewController.previousViewControllerID = TrackedViewController.currentViewControllerID
TrackedViewController.currentViewControllerID = self.screenIdentifier
}
var screenIdentifier: String {
return "Default Screen" // TODO: every view controller must override this method and have unique identifier
}
}
Also you may replace strings with some enumeration or something. Combining them with some associated values could then create quite a powerful tool.

iOS - How to use a small view in different view controllers in Swift

I have a progress bar (with its own controller). This bar is supposed to be shown in different views depending on which view is visible. As the progress will be same, If possible I don't want to create many progress bar in many views rather I want to use same instance in all these views. Also in that way when I need to change any property of the progress bar it will be reflected commonly, which is required.
Please suggest me how can I use this common view. And also if my strategy is wrong, what would be the better design for such scenarios.
1) Well you have 2 options. You can declare a new Class ViewBox (or whatever name) and then use that inside your code
First View Controller
var box:ViewBox = ViewBox()
When you segue or transition to your next screen, you can have a predefined variable var box:ViewBox!. Then say when you press a button, the button has a function called transition.
//Now setup the transition inside the Storyboard and name the identifier "toThirdViewController"
override func prepareForSegue(segue:UIStoryboardSegue, sender:AnyObject?) {
if(segue.identifier == "toThirdViewController") {
var vc = segue.destinationViewController as! `nextViewController` //The class of your next viewcontroller goes here
vc.box = self.box
}
//Since The SecondViewController doesn't need ViewBox, we don't need it there.
}
where
nextViewController:UIViewController {
var box:ViewBox!
}
Or you could do a much simpler way and that is to look up a UIPageViewController :)

How to pass data from one tabbar to another in swift?

I want to pass data from one tabBar controller to another,
I am switching tabBar using tabBarController?.selectedIndex = 0
I tried many option but unable to pass data to another tab, is there any simple solution like we pass data using navigation controller?
Tabs are usually some custom UIViewControllers. From these view controllers (tabs) you can also get access to the UITabBarController with something like:
if let mainController = UIApplication.sharedApplication().delegate?.window??.rootViewController as? YourMainTabBarControllerClass {
mainController.someVariable = 123
}
Here you have to be careful, because the tab bar controller may not be the rootViewController, see this question for more details.
In order to store some properties in the UITabBarController you have to implement your own class by extending UITabBarController and then set the custom class in the StoryBoard. The class will then look like:
class YourMainTabBarControllerClass: UITabBarController {
// some custom variables here...
var someVariable = 0
...
}

MonoTouch.Dialog with UISplitViewController

I'm creating universal app with MonoTouch. When running on iPad I use UISplitViewController and build multi level menu in master view (on the left side) with MonoTouch.Dialog.
Problem is, that when I touch first root element it opens new view which covers whole screen instead of being inside master split view.
Question is, how can I make so next root element opens inside same view as it's parent?
All the examples I could find usually has one level menu on the master view so when you touch it displays something on the detail view.
Hope this makes sense.
Let's say you have an UISplitViewController and your CustomViewController.
UISplitViewController split = ...;
CustomViewController controller = ...;
If you want to push the new controller on top of the current (master) one then use:
var root = new RootElement ();
var dvc = new DialogViewController (UITableViewStyle.Plain, root, true);
dvc.ActivateController (controller);
If you want to show the new controller in the details (right) section then use something like:
UISplitViewController split = ...;
var about = new StringElement ("About");
about.Tapped += delegate {
split.ViewControllers = new UIViewController [] {
split.ViewControllers [0],
controller
};
};
So you want your, I guess table, in the master to populate a new masterview on touch event?
I'm not familiar with .dialog but i've given an example as i know it:
take your rootviewcontroller.parentviewcontroller.splitviewcontroller and then populate the viewcontrollers[0]
var split =(uisplitviewcontroller)rootviewcontroller.parentviewcontroller.splitviewcontroller;
var nav = (uinavigationcontroller)split.viewcontrollers[0];
nav.pushviewcontroller(_yourView_);

Resources