I am a new iOS developer so please bear with me if I seem a little ignorant.
I am trying to make an app for a gallery. I want to use iBeacons in each category of the gallery. I know how to make this all happen if I am only using one view controller. I can make it range for the beacon and once in a certain range send a pop up stating "You have entered the "XXXX" area. Would you like to view these exhibits?"
If the user presses yes, it will take them to it. However, the problem I am running into is that I need to have quite a few view controllers. So How can I get the ranging to happen in the background of all of them? Should I create a separate Swift file and do all the ranging there and then call that class in each view? Or should (or even could) I do all the beacon code in the app delegate.
The next problem that I have is how to segue to the "category" view controller when a user is in a view controller that doesn't have the actual segue? Say VC 1 has a segue to VC 2 with identifier #3. Can I call the segue with ID #3 from VC 5, for an example? Or is it better to instantiate the views?
Will appreciate any tips.
This kind of centralized logic fits well into the AppDelegate as it is designed to handle global app logic. It is easy and a common practice to set up beacon monitoring and ranging in the didFinishLaunching callback.
To launch specific view controllers, it is easiest to instantiate and present them programmatically (rather than using a segue) when a change is needed based on beacon detection in a callback in the AppDelegate.
Related
My app consists of two views. The first one is a GMSMapView and the second one is used to connect to a Bluetooth device that sends coordinates.
After the Bluetooth device is connected, I use a delegate to send the information back to the map view and move a marker around. To transition between views I was previously using segues, this didn't stop the Bluetooth view controller and the data made its way like I wished to the map view.
I ran into the problem of my map view being reinitiated so I decided to use a navigation controller. Now I use a push segue to get to my second view, and pop to come back to the same instance of the first one. Great, that worked! The issue I have now is that popping the second view seems to stop it completely from running in the background like it used to. Is there a way to keep it running in the background like it did before?
What I'm currently using to pop the second view is
self.navigationController?.popViewControllerAnimated(true)
Any idea would be appreciated! Thanks!
A popped view controller does not "stop running". It is returned to you, and if you don't retain it, it is completely destroyed.
If you don't want that to happen, retain it when it is returned. You are currently ignoring the returned view controller:
self.navigationController?.popViewControllerAnimated(true)
Instead, keep a reference to it:
self.mySecondViewController =
self.navigationController?.popViewControllerAnimated(true)
Be warned, however, that this is a very unusual architecture. You will not be able to use the storyboard segue to push again, because it will push a different copy. It would be better to abandon your navigation controller architecture entirely, as it is completely unsuited to the idea of a view controller persisting after it is popped. If you want an architecture where two view controllers persist simultaneously, you would be better off using a UITabBarController — or, even better, reorganize your app completely. The notion that you need the view controller to persist after being popped is a "bad smell": it means that you have put the functionality in the wrong place. Put the functionality in a place that does persist, rather than forcing the view controller to persist in some artificial way.
I have been searching all over the web but I can't seem to find the answer to this.
Currently i am using presentViewController to start new ViewControllers, but on certain view controllers i do not dismiss it and call over it. I currently am not using any navigation controllers or anything like that.
I am just worried that if I call the same viewController again via presentViewController, that the same viewController would have 2 running instances.
Is it possible? Or does the iOS framework automatically reuse the idle viewController?
If so, how do i remove the idle view controllers?
Thank you! (I was holding back my question and tried to find it all over the web, so if you can point me in the right direction, it would be very helpful thanks!)
iOS will not reuse your view controller, you can easily check it yourself by printing your view controller in viewDidLoad, you will notice first that viewDidLoad is called every time, and next that all objects have different addresses.
Unless you create thousand of them, or the navigation of your app doesn’t let you come back to an “idle” view controller, I would not say this is an issue though.
I don’t see any clean way to remove a view controller from the memory without calling “dismiss”. You could try to:
- “refresh” your view with new data.
- use something like UIPageViewController if the workflow of your app allows this kind of behaviour.
- rework the navigation so you can dismiss the view before calling another one
Good luck
I have a presentedViewController on top of the root view controller when the app gets dismissed. (e.g. User navigates to another app or goes back to the home screen.)
I would like to nil it out when the user reactivates the app without it being visible to them. Calling -dismissViewControllerAnimated: is not an option because it only works if the view controller is visible, and I'd like to do it sooner and specifically only in application:openURL:sourceApplication:annotation: and otherwise let the user continue their workflow in the modal view.
Are there any tricks I can use?
According to your comment, the only actual issue is what happens when the app receives application:openURL:sourceApplication:annotation: and is thus brought to the front.
In that case, simply adjust your interface in application:openURL:sourceApplication:annotation: - that is part of its purpose, to allow you to do that. You will be given some time before the "snapshot" is torn away, so if the adjustment involved is to dismiss an existing modal view, dismiss it without animation and there you are.
The user will still see the modal view for a moment, but not really - what the user is seeing is not your interface but the "snapshot" that was created by the system when the app when into the background. The "snapshot" is removed to reveal the actual interface (with a nice crossfade effect in iOS 7).
If the "snapshot" itself is problematic there are ways of preventing it from being taken, but it doesn't sound to me like this is that kind of situation.
(By the way, this raises the question of how the presented view is to know that it must be dismissed. The initial main action is in your app delegate, which is probably some conceptual distance away from the presented view. This would be an appropriate situation in which to use an NSNotification to communicate across this distance.)
I would like to move back to my main view using a segue. When the home button is pressed and the app enters the background.... then later the user wishes to open the application again bringing it to the foreground I would like a segue to be run which takes them from whatever view they were in back to the 'main view'. I dont mind using multiple segues... or how could I access these segues in the app delegate for example.
What is the best method for this? Thankyou! beer and points for everyone who gives a good answer ;).
You may implement the applicationWillEnterForeground:application: method (from the UIApplicationDelegate protocol). This method is called whenever your application's state changes from backgo to inactive state (before it goes to active).
In this method you could call performSegueWithIdentifier:identifier sender:. If you have a segue from each possible view back to your main view, your are done.
However, unless your application has a very complex state that would need lots of time to reconstruct, I would recommend to do general a re-initialization of your application in application:didFinishLaunchingWithOptions: or applicationDidBecomeActive:. In this way it is easier to preserve a consistent state.
Scenario:
Storyboard with UINavigationController as initial controller.
MainVC (navigation controller's root vc) needs the user to choose a location on a map.
MainVC pushes a VC containing a MapKit map and adds itself as listener for a notification the MapVC sends out when the user chooses a location.
MapKit is a memory hog, we all know that. iOS gives me a memory warning, I do all the things that need to be done, then iOS deallocates all it can deallocate, including the MainVC.
MapVC sends out the notification but there's nobody to listen to it. The location the user chose is lost, like tears in rain.
Given this, what's a reliable way to pass that location data when going back to MainVC? I even thought of writing it down to ~/tmp (which is something I use to do when dealing with large amount of data like images) but that seems like a waste of machinery. Isn't there a mechanism I can hook to, like an event fired when the navigation controller goes back to the previous VC? Like, having access to something like the prepareForSegue: but on the opposite direction would be nice.
EDIT I tried going for delegation but it seems my delegate gets released nonetheless. Am I stuck with having to write to ~/tmp?
See my answer here for a detailed explanation of setting up a delegate and delegate protocol - here