How to use GMSPlacePickerViewController class? - swift

I created the picker as follows:
let placePicker = GSMPlacePickerViewController(config: config)
placePicker.delegate?.placePicker(viewController: GSMPlacePickerViewController, didPick: GSMPlace)
In the second line of the code above, how can I store the place the user picks inside a variable of my own so later I can access its properties like the coordinates?
I am confused on how to implement GSMPlacePickerViewController method and couldn't find examples online.
As from the GSMPlacePickerViewController docs, it says that I don't have to implement the first parameter and I could leave it empty if I understood it correctly
Implementations of this method should dismiss the view controller as
the view controller will not dismiss itself.
So my problem now, is storing the user selected location in a variable of my own.
How should I go to achieving that?

Add GMSPlacePickerViewControllerDelegate to your view controller like so:
class YourViewController: GMSPlacePickerViewControllerDelegate {
}
Then add the delegate method within said VC which will be called when the user picks the place. You then dismiss and access place data like below:
func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) {
placePicker.dismiss(animated: true, completion: nil)
let location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)
}

Related

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

Google Places Autocomplete Delegate not set

I am setting the delegate of the autocomplete view controller to the current class, which has an autocompleteviewcontrollerdelegate extension. This has has always worked in the past, but recently I am getting an error message printing out that says the delegate for the autocomplete controller is not set and I can confirm the delegate is no longer being called. I have the print(self) line to check that I am in fact setting the correct class to be the delegate. I have this exact same setup in another part of my app that is working fine. Any suggestions on how to debug this issue?
#objc func searchButton() {
print(self)
let acController = GMSAutocompleteViewController()
acController.delegate = self
acController.autocompleteBounds = getBounds(latitude: latitude!, longitude: longitude!)
// Specify a filter.
//let filter = GMSAutocompleteFilter()
//filter.type = establishment
//acController.autocompleteFilter = filter
present(acController, animated: true, completion: nil)
}
In my viewwillDisappear method I pop the view controller so that if the user navigated away from the page with the tab bar controller the next time they navigate to the page they will be on the main page. Whenever the autocomplete view controller was appearing the parent viewcontroller was getting popped off the stack and killing off the delegate.

Swift macOS SegmentedControl Action not getting called

Description
I am trying to use NSSegmentedControls to transition between Child ViewControllers. The ParentViewController is located in Main.storyboard and the ChildViewControllers are located in Assistant.storyboard. Each ChildViewController has a SegmentedControl divided into 2 Segments and their primary use is to navigate between the ChildViewControllers. So they are set up as momentaryPushIn rather than selectOne. Each ChildViewController uses a Delegate to communicate with the ParentViewController.
So in the ParentViewController I added the ChildViewControllers as following:
/// The View of the ParentViewController configured as NSVisualEffectView
#IBOutlet var visualEffectView: NSVisualEffectView!
var assistantChilds: [NSViewController] {
get { return [NSViewController]() }
set(newValue) {
for child in newValue { self.addChild(child) }
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
addAssistantViewControllersToChildrenArray()
}
override func viewWillAppear() {
visualEffectView.addSubview(self.children[0].view)
self.children[0].view.frame = self.view.bounds
}
private func addAssistantViewControllersToChildrenArray() -> Void {
let storyboard = NSStoryboard.init(name: "Assistant", bundle: nil)
let exampleChild = storyboard.instantiateController(withIdentifier: "ExampleChild") as! ExampleChildViewController
let exampleSibling = storyboard.instantiateController(withIdentifier: "ExampleSibling") as! ExampleSiblingViewController
exampleChild.navigationDelegate = self
exampleSibling.navigationDelegate = self
assistantChilds = [exampleChild, exampleSibling]
}
So far so good. The ExampleChildViewController has an NSTextField instance. While I am in the scope of the TextField, I can trigger the action of the SegmentedControls. Its navigating forward and backward as it should. But once I leave the scope of the TextField I can still click the Segments, but they are not triggering any action. They should be able to navigate forward and backward even if the TextField is not the current "First Responder" of the application. I think I am missing something out here, I hope anyone can help me with this. I know the problem is not the NSSegmentedControl because I am seeing the same behavior with an NSButton, which is configured as Switch/Checkbox, in the SiblingViewController. I just don't have any idea anymore what I am doing wrong.
It`s my first time asking a question myself here, so I hope the way I am doing is fine for making progress with the solution. Let me know if I can do something better/different or if I need to provide more information about something.
Thanks in advance!
Additional Information
For the sake of completeness:
The ParentViewController itself is embedded in a ContainerView,
which is owned by the RootViewController. I can't imagine this does
matter in any way, but this way we are not missing something out.
I am actually not showing the navigation action, because I want to
keep it as simple as possible. Furthermore the action is not problem,
it does what I want it to do. Correct me if I am wrong with this.
Possible solutions I found while researching, which did not work for me:
Setting window.delegate of the ChildViewControllers to NSApp.windows.first?.delegate
Setting the ChildViewController to becomeFirstResponder in its func viewWillAppear()
visualEffectView.addSubview(self.children[0].view, positioned: NSWindow.OrderingMode.above, relativeTo: nil)
Related problems/topics I found while researching:
Basic segmented control not working
Adding and Removing Child View Controllers
NSSegmentedControl - Odd appearance when placed in blur view
How to set first responder to NSTextView in Swift?
How to use #selector in Swift 2.2 for the first responder
Accessing methods, actions and/or outlets from other controllers with swift
How to use Child View Controllers in Swift 4.0 programmatically
Container View Controllers
issues with container view
Control a NSTabViewController from parent View
How to detect when NSTextField has the focus or is it`s content selected cocoa
SOLUTION
let parentViewControllerInstance = self.parent as! ParentViewController
segmentedControl.target = parentViewControllerInstance
In my case I just had to set the delegate as the target of the sendAction method.
Background
Ok, after hours of reading the AppKit Documentation I am now able to answer my own question.
First, debugging the UI showed that the problem was definitely not in the ViewHierarchy.
So I tried to think about the nature of NSButton and NSSegmentedControl. At some point I noticed that both are subclasses of NSControl.
class NSSegmentedControl : NSControl
class NSButton : NSControl
The AppKit Documentation says:
Discussion
Buttons are a standard control used to initiate actions within your app. You can configure buttons with many different visual styles, but the behavior is the same. When clicked, a button calls the action method of its associated target object. (...) You use the action method to perform your app-specific tasks.
The bold text points to the key of the solution – of its associated target object. Typically I define the action of an control item like this:
button.action = #selector(someFunc(_:))
This causes the NSControl instance to call this:
func sendAction(_ action: Selector?, to target: Any?) -> Bool
Parameter Description from the documentation:
Parameters
theAction
The selector to invoke on the target. If the selector is NULL, no message is sent.
theTarget
The target object to receive the message. If the object is nil, the application searches the responder chain for an object capable of handling the message. For more information on dispatching actions, see the class description for NSActionCell.
In conclusion the NSControl instance, which was firing the action method (in my case the NSSegmentedControl), had no target to send its action to. So it was only able to send its action method across the responder chain - which obviously has been nil while the first responder was located in another view.

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.

why pass viewController as variable?

First of all I have to say I am really new to swift and Objective C.I am learning them by myself.
I have a question for this code
I have a delegate in my SettingViewController called "settingsViewControllerFinished" and it pass the whole controller as a variable.
the code like this:
in my SettingViewController.swift
protocol SettingViewControllerDelegate: class {
func settingsViewControllerFinished(settingsViewController: SettingsViewController)
}
#IBAction func close(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
self.delegate?.settingsViewControllerFinished(self)
}
I am confused.What did you mean if you pass the whole controller as a variable?(maybe the question is silly for you)
in my viewController:
func settingsViewControllerFinished(settingsViewController: SettingsViewController)
{
self.brushWidth = settingsViewController.brush
self.opacity = settingsViewController.opacity
self.red = settingsViewController.red
self.green = settingsViewController.green
self.blue = settingsViewController.blue
}
I guess the reason is:I pass everything in SettingViewController to ViewController so that I could use the variables in SettingViewController.
Am I rihgt?
Generally you are correct, yes: passing the SettingViewController back to its delegate enables the original caller to not have to keep a reference to the created and shown SettingViewController since the delegate method sends the relevant information along already.
But there is more: In some cases of delegates this style is useful for something different. Imagine a click handler consisting of a function func somethingGotClicked(sender:YourSenderType). If your class creates multiple instances of YourSenderType and shows them at the same time registering itself as their delegate there would be no way to know which one got clicked if there was no sender parameter. In some func somethingGotClicked() you would not know which one got clicked. That capability is often needed when showing multiple UITableView or UICollectionView is one single view with one single instances set as their delegate.