I have two UIAlertControllers that can potentially be displayed – one for registering an account, and one for logging into it. They can be presented with an optional message.
func present(alertController: UIAlertController? = nil, message: String? = nil) {
self.currentAlertController = alertController ?? self.currentAlertController
self.currentAlertController.message = message
(UIApplication.shared.delegate as! AppDelegate).window?.rootViewController?.present(self.currentAlertController, animated: true, completion: nil)
}
And it look like the message is carried through the function.
But then it doesn't display.
I can't tell if I'm missing something basic, or there's just something about UIAlertController I'm not aware of.
Switching the present action and the setting of the message did the trick.
func present(alertController: UIAlertController? = nil, message: String? = nil) {
self.currentAlertController = alertController ?? self.currentAlertController
(UIApplication.shared.delegate as! AppDelegate).window?.rootViewController?.present(self.currentAlertController, animated: true, completion: nil)
self.currentAlertController.message = message
}
Another thing is, when initializing the UIAlertController to begin with, if you want the message to start blank but allow it to be updated later, the message should be "" as opposed to nil.
Related
Hi I am writing the following code to refer a friend through SMS.
When I click on cell, the sms app opens with text but when again I tried for second time, it shows white color screen.
Here is my code
var controller1 = MFMessageComposeViewController()
extension ReferaFriendController:UICollectionViewDelegate,UICollectionViewDataSource,MFMessageComposeViewControllerDelegate
{
if indexPath.item == 0
{
if MFMessageComposeViewController.canSendText() {
let urlToShare = self.referalmodeldata[0].referralCodeOnly
controller1.body = "Hey I just gave an Awesome Assessment on App you can also try it. I scored , Try to beat my score \(String(describing: urlToShare))"
controller1.messageComposeDelegate = self
self.present(controller1, animated: true, completion: nil)
}
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
self.dismiss(animated: true, completion: nil)
}
}
As far as I can see, there's no need to keep a reference to the MFMessageComposeViewController. Just move it to be created at the point you need it, inside your if closure:
if MFMessageComposeViewController.canSendText() {
let controller = MFMessageComposeViewController()
// ...
}
I'm working for an app that has users. One of the functionalities is to allow a user to log out and be redirected to the first page. I came across the problem when a user logs out, a toast message "You logged out" should be displayed on the first view of the app and receiving the command from a different page. Basically a toast message that can work with all the views, not only with the current one.
I managed to call a toast function after a user logs out but it won't show the message because the current view is dismissed before to have the chance showing it.
This is the function called:
func showToast(controller: UIViewController, message : String, seconds: Double) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.view.backgroundColor = UIColor.black
alert.view.alpha = 0.6
alert.view.layer.cornerRadius = 15
controller.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
}
}
If you dont know which the current presented VC is you could use this extension here:
extension UIWindow {
func topViewController() -> UIViewController? {
var top = self.rootViewController
while true {
if let presented = top?.presentedViewController {
top = presented
} else if let nav = top as? UINavigationController {
top = nav.visibleViewController
} else if let tab = top as? UITabBarController {
top = tab.selectedViewController
} else {
break
}
}
return top
}
}
Then you can call it it this way:
if let topVC = UIApplication.shared.keyWindow?.topViewController() {
topVC.present(alert, animated: true)
}
Another option is that you pop/dismiss your viewcontroller after you dismissed your alert:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
// popViewController or dismiss here
}
Since UIAlertView is deprecated I want to replace it by UIAlertController in my old libraries.
But it is not always obvious to do. For example I have those two functions, doing a very similar task.
showAlertViewMessageBox uses UIAlertView and showMessageBox uses UIAlertController:
func showAlertViewMessageBox(_ msg:String, title:String, caller:UIViewController) {
let userPopUp = UIAlertView()
userPopUp.delegate = caller
userPopUp.title = title
userPopUp.message = msg
userPopUp.addButton(withTitle: "OK")
userPopUp.show()
}
func showMessageBox(_ msg:String, title:String, caller:UIViewController) {
let attribMsg = NSAttributedString(string: msg,
attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 23.0)])
let userPopUp = UIAlertController(title:title,
message:nil, preferredStyle:UIAlertController.Style.alert)
userPopUp.setValue(attribMsg, forKey: "attributedMessage")
let alertAction = UIAlertAction(title:"OK", style:UIAlertAction.Style.default,
handler:{action in})
alertAction.setValue(UIColor.darkGray, forKey: "titleTextColor")
userPopUp.addAction(alertAction)
caller.present(userPopUp, animated: true, completion: nil)
}
I want to use showMessageBox as much as possible. But I have this unhappy situation:
In the following code:
//showMessageBox(usrMsg, title: popTitle, caller: self)
showAlertViewMessageBox(usrMsg, title: popTitle, caller: self)
quitViewController()
When using showAlertViewMessageBox, the message will pop up and stay there until I click the OK button.
(This is the behavior I want)
When using showMessageBox, the message will pop up as a blink and disappear without waiting for me to click the OK button.
(This is NOT the behavior I want)
How should I modify showMessageBox to get the behavior I want?
Assuming you are dismissing the viewController inside quitViewController() method, it is very natural that the message will pop up as a blink and disappear without waiting for me to click the OK button. As your quitViewController() method is executed without waiting for the OK button clicked.
One way, is adding a parameter to handle OK button clicking:
func showMessageBox(_ msg:String, title:String, caller:UIViewController, onOk: #escaping ()->Void) {
let attribMsg = NSAttributedString(string: msg,
attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 23.0)])
let userPopUp = UIAlertController(title:title,
message:nil, preferredStyle:UIAlertController.Style.alert)
userPopUp.setValue(attribMsg, forKey: "attributedMessage")
let alertAction = UIAlertAction(title:"OK", style:UIAlertAction.Style.default,
handler:{action in onOk()}) //<- Call the Ok handler
alertAction.setValue(UIColor.darkGray, forKey: "titleTextColor")
userPopUp.addAction(alertAction)
caller.present(userPopUp, animated: true, completion: nil)
}
Use it as:
showMessageBox(usrMsg, title: popTitle, caller: self) {
self.quitViewController()
}
By the way, attributedMessage of UIAlertController and titleTextColor of UIAlertAction are private properties, so using this code may risk your app to be rejected by using private APIs.
I have an alarm clock app. It has 2 VC. VC1 is a menu VC that linked with VC2. In VC2 there's setting of alarm clock. So I have troubles with getting local notifications.
For example, if I set Alarm Clock on VC2 then I move to VC1 and then go to Home Screen I will receive a notification on the top of the screen. After clicking on notification I will move to VC1 and I will get a message. But I will get an error 'Could not cast value of type 'MyApp.VC1' (0x10ee97730) to 'MyApp.VC2' (0x10ee96bd0)'. If I set Alarm Clock on VC2 then I move to Home Screen I will receive a notification on the top of the screen. After clicking on notification I will move to VC2 and I will get a message and everything will be fine.
Other problem is setting Alarm clock on VC2 and moving to VC1 without moving to Home Screen. When time will I come my app just crashing with same error 'Could not cast value of type 'MyApp.VC1' (0x10ee97730) to 'MyApp.VC2' (0x10ee96bd0)'
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
let storageController = UIAlertController(title: "Alarm", message: nil, preferredStyle: .alert)
var soundName: String = ""
var index: Int = -1
if let userInfo = notification.userInfo {
soundName = userInfo["soundName"] as! String
index = userInfo["index"] as! Int
}
playSound(soundName)
let stopOption = UIAlertAction(title: "OK", style: .default) {
(action:UIAlertAction)->Void in self.audioPlayer?.stop()
let mainVC = self.window?.visibleViewController as! MainAlarmViewController
storageController.addAction(stopOption)
(self.window?.visibleViewController as! MainAlarmViewController).present(storageController, animated: true, completion: nil)
}
Does anybody know how to resolve it?
When I getting an error I see highlight of this line:
(self.window?.visibleViewController as! MainAlarmViewController).present(storageController, animated: true, completion: nil)
Thank you so much!
P.S. Maybe is it possible to make a notification on the top of a screen with a link to VC2 when app in foreground or app in VC1?
Also sometimes I'm getting a message 'Warning: Attempt to present on whose view is not in the window hierarchy!'
Replace this line
(self.window?.visibleViewController as! MainAlarmViewController).present(storageController, animated: true, completion: nil)
with following code
if let viewController = self.window?.visibleViewController {
if viewController is MainAlarmViewController {
// view controller is MainAlarmViewController
} else {
// view controller is not MainAlarmViewController
}
viewController.present(storageController, animated: true, completion: nil)
} else {
print("Something wrong. Window can't provide visible view controller")
}
I present a UIAlertController, appearing for about half a second and disappearing, before I need to touch the OK button.
Any idea about what could cause this?
For reference, the code is below, I have been using it many times, in the past. Apart that this time I pass a caller parameter.
func showMessageBox(msg:String, title:String, caller:UIViewController) {
let attribMsg = NSAttributedString(string: msg,
attributes: [NSFontAttributeName : UIFont.systemFontOfSize(23.0)])
let userPopUp = UIAlertController(title:title,
message:nil, preferredStyle:UIAlertControllerStyle.Alert)
userPopUp.setValue(attribMsg, forKey: "attributedMessage")
userPopUp.addAction(UIAlertAction(title:"OK", style:UIAlertActionStyle.Default,
handler:{action in}))
caller.presentViewController(userPopUp, animated: true, completion: nil)
}
I just tried the code here and it worked fine - the alert controller waits for me to click the button before going away. Is it possible that whatever is presenting it is also dismissing it by accident? Or perhaps that the view controller inside caller is itself being dismissed?