Detect when all layers have been added to mapbox map - swift

It seems like all of the events in v10, listed below, fire before annotations/polygon fill layers/etc appear on the map. How can I detect when everything has been loaded/added to the map (so I can display a loading screen over the map while the loading happens)?
mapView.mapboxMap.onNext(event: .sourceAdded, handler: {})
mapView.mapboxMap.onNext(event: .sourceDataLoaded, handler: {})
mapView.mapboxMap.onNext(event: .renderFrameFinished, handler: {})
mapView.mapboxMap.onNext(event: .cameraChanged, handler: {})
mapView.mapboxMap.onNext(event: .styleDataLoaded, handler: {})
mapView.mapboxMap.onNext(event: .styleLoaded, handler: {})
mapView.mapboxMap.onNext(event: .mapIdle, handler: {})
mapView.mapboxMap.onNext(event: .mapLoaded, handler: {})
mapView.mapboxMap.onNext(event: .mapLoadingError, handler: {})
mapView.mapboxMap.onNext(event: .renderFrameStarted, handler: {})
mapView.mapboxMap.onNext(event: .resourceRequest, handler: {})
mapView.mapboxMap.onNext(event: .sourceAdded, handler: {})
mapView.mapboxMap.onNext(event: .sourceRemoved, handler: {})
mapView.mapboxMap.onNext(event: .styleImageMissing, handler: {})
mapView.mapboxMap.onNext(event: .styleImageRemoveUnused, handler: {})
None of the above event triggers work at the point where all my added layers/annotations appear on the map. Any help is much appreciated!

Related

Using a escape function in Swift to allow the use of parameters

I am new to this escape function in Swift, but I follow a tutorial and I use the following function below: (the function is working for me)
static func showThreeOptions(messageText: String, titleOne:String, titleTwo: String, actionOne: #escaping () -> (Void), actionTwo: #escaping () -> (), currentView: UIViewController ) {
// create the alert
let alert = UIAlertController(title: "Alerta", message: messageText, preferredStyle: UIAlertController.Style.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: titleOne, style: UIAlertAction.Style.default, handler: { (alert) in
actionOne()
} ))
alert.addAction(UIAlertAction(title: titleTwo, style: UIAlertAction.Style.default, handler: { (alert) in
actionTwo()
} ))
alert.addAction(UIAlertAction(title: "Cancelar", style: UIAlertAction.Style.destructive, handler: nil))
// show the alert
currentView.present(alert, animated: true, completion: nil)
}
Now, I want to change the actionTwo() to actionTwo(number:Int),
but I don't know how to change the signature actionTwo: #escaping () -> ()
How can I change the signature
actionTwo: #escaping () -> () to allow to be able to call actionTwo(number:Int) ?
-----UPDATE-----
I create the function
actionTwo(2) and it works. Thank you #RobNapier
But there is another problem now.
I call the function
AlertActions.showThreeOptions(
messageText: "Resenha Finalizada.",
titleOne: "Marcas/Fotos",
titleTwo: "Editar",
actionOne: self.someHandlerOne,
actionTwo: self.someHandlerTwo(2),
currentView: self
)
This is the functions
func someHandlerOne() {
print("test")
}
func someHandlerTwo(_ id:Int) {
print("test2")
}
Now I get the following error when I call someHandlerTwo(_ id:Int)
Cannot convert value of type '()' to expected argument type '(Int) -> ()'
How can I fix that error?
-----UPDATE 2-----
I find out how to use a escaping function now
func notImplemented(resDado_id: Int) -> () {
print(resDado_id)
}
Change #escaping () -> () to #escaping (Int) -> (). Instead of something that takes no parameters, you want something that takes one.
It's a little nicer to use Void for return values that are (), like (Int) -> Void, but it means the same thing.
My suggestion is a different approach:
Write an extension of UIViewController and use the UIAlertAction handler signature for actionOne and actionTwo.
This is still more versatile and the UIAlertAction handler closures don't escape
extension UIViewController {
func showThreeOptions(messageText: String, titleOne:String, titleTwo: String, actionOne: ((UIAlertAction) -> Void)? = nil, actionTwo: ((UIAlertAction) -> Void)? = nil) {
// create the alert
let alert = UIAlertController(title: "Alerta", message: messageText, preferredStyle: .alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: titleOne, style: .default, handler: actionOne))
alert.addAction(UIAlertAction(title: titleTwo, style: .default, handler: actionTwo))
alert.addAction(UIAlertAction(title: "Cancelar", style: .destructive, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
}
The closures can even be declared as functions for example
func actionOne(action : UIAlertAction) {
//
}
Edit:
You don't need to pass a parameter, you can create the handler inline and capture the id
func deleteSomething(at id: Int) {
let handler : (UIAlertAction) -> Void = { action in
db.deletarResDados(id: id)
}
showThreeOptions(messageText: "Resenha Finalizada.",
titleOne: "Marcas/Fotos",
titleTwo: "Editar",
actionOne: nil,
actionTwo: handler)
}

How to create a drop down menu

How can I create a menu like this using swift?
Example
It's alertController with actionSheet. User this method in your button action for example.
func handleAlert()
let alertController = UIAlertController(title: "Change Profile Photo", message: nil, preferredStyle: .actionSheet)
//First action
alertController.addAction(UIAlertAction(title: "Remove current photo", style: .destructive, handler: { (_) in
// Your remove photo code here
}))
alertController.addAction(UIAlertAction(title: "Import From Facebook", style: .default, handler: { (_) in
// Your import from facebook code here
}))
//Cancel action
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true, completion: nil)
}

How to enable a Uialertview specific button in iOS after it is clicked, using Swift?

on Button clear history I want to enable other 2 buttons. I am new in iOS.
let alert = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
let markAction = UIAlertAction(title: "Mark as Urgent", style: .default, handler: { (action) in
})
let resolveAction = UIAlertAction(title: "Resolvethe conversion", style: .default, handler: { (action) in
})
markAction.isEnabled = false
resolveAction.isEnabled = false
alert.addAction(markAction)
alert.addAction(UIAlertAction(title: "Clear history", style: .default, handler: { (action) in
alert.actions.map {$0.isEnabled = true}
}))
self.present(alert, animated: true, completion: nil)
}
You can enable your actions in the clear button completion handler and present again your alert because you cannot avoid the dismiss:
let alert = UIAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
let markAction = UIAlertAction(title: "Mark as Urgent", style: .default, handler: { (action) in
// TODO: Your action
})
markAction.isEnabled = false
alert.addAction(markAction)
alert.addAction(UIAlertAction(title: "Clear history", style: .default, handler: { (action) in
alert.actions.map {$0.isEnabled = true}
self.present(alert, animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)

Dismiss Alert Programmatically Swift

I need a little help with a UIAlert. I get an error "UIAlertController can only have one action with a style of UIAlertActionStyleCancel". I know it is because I am initiating this alert outside of the function, but unsure how to fix it. How can I get access to the alert within the if blah < 80 { conditional?
let alertView = UIAlertController(title: "Blah", message: "", preferredStyle: UIAlertControllerStyle.Alert)
#IBAction func blahButtonPressed(sender: AnyObject) {
alertView.addAction(UIAlertAction(title: "Do Something", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Do Something 2", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { (action: UIAlertAction!) in
// I have code here
}))
presentViewController(alertView, animated: true, completion: nil)
}
Later in the code I get values via Bluetooth and need to dismiss the Alert if a value is below 80.
if blah < 80 {
alertView.dismissViewControllerAnimated(true, completion: nil)
}
I'm not 100% but does it work when you only press the button once? If so, then it may be because you are adding the actions to your alertView inside the #IBAction. Instead, you may want to try moving the addition of the UIAlertAction's outside of the #IBAction and only presenting the alert view inside of it. Like so:
let alertView = UIAlertController(title: "Blah", message: "", preferredStyle: UIAlertControllerStyle.Alert)
alertView.addAction(UIAlertAction(title: "Do Something", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Do Something 2", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { (action: UIAlertAction!) in
// I have code here
}))
#IBAction func blahButtonPressed(sender: AnyObject) {
presentViewController(alertView, animated: true, completion: nil)
}
This way the UIAlertAction's don't get added every single time the "blahButton" is pressed (which would result in more than one UIAlertAction with style of "UIAlertActionStyleCancel")
Here is how I fixed it if anyone comes accross this.
var newAlert: AnyObject?
#IBAction func blahButtonPressed(sender: AnyObject) {
let alertView = UIAlertController(title: "Blah", message: "", preferredStyle: UIAlertControllerStyle.Alert)
alertView.addAction(UIAlertAction(title: "Do Something", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Do Something 2", style: .Default, handler: { (action: UIAlertAction!) in
// I have code here
}))
alertView.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { (action: UIAlertAction!) in
// I have code here
}))
newAlert = alertView
presentViewController(alertView, animated: true, completion: nil)
}
// When I need to close. If blah is below 80
if blah < 80 {
if let newAlertView = newAlert as? UIAlertController {
newAlertView.dismissViewControllerAnimated(true, completion: nil)
}
}

Can a UIAlertAction trigger a function?

Is it possible to connect a function to an UIAlertAction?
So after a user clicks the OK button it performs an action? Isn't this what the handler parameter does?
let alert: UIAlertController = UIAlertController(title: "Email already registered", message: "Please enter a different email", preferredStyle: .alert)
let okButton = UIAlertAction(title: "OK", style: .default, handler: backToLogin())
alert.addAction(okButton)
self.presentViewController(alert, animated: true, completion: nil)
...
func backToLogin() {
self.performSegueWithIdentifier("toLoginPage", sender: self)
}
You can use a function as the handler, but it needs to have the correct type. Also you must not call it when you pass it as an argument, i.e., instead of handler: backToLogin() (which would set the return value of backToLogin as the handler) you would have handler: backToLogin without the ().
The following should work:
func backToLogin(alertAction: UIAlertAction) {
self.performSegueWithIdentifier("toLoginPage", sender: self)
}
let okButton = UIAlertAction(title: "OK", style: .Default, handler: backToLogin)
But having to change backToLogin might defeat the purpose, so you could just use a closure:
let okButton = UIAlertAction(title: "OK", style: .Default) { _ in
self.backToLogin()
}
You need to enter the handler
let okButton = UIAlertAction(title: "OK", style: .Default, handler: {
(UIAlertAction) in
self.backToLogin()
})
}
See this answer for more info: Writing handler for UIAlertAction