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?
Related
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 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.
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 coded my application with Swift 2. When i was trying to create my application, i used this code after user login successfully
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("home") as! UITabBarController
self.presentViewController(vc, animated: true, completion: nil)
vc is a UITabBarController which has 3 UIViewController. After TabBar appears only selected TabBar's item's image appears. All the other images appears after 10 seconds or if i touch any of them it appears. If I set TabBarController as an initial view images appears successfully.
I checked the RAM status and application uses 14.5 mb on iPhone 6 plus so i don't think happens because of memory leak.
I searched everywhere but i couldn't find any problem same as mine.
SOLVED:
I was using Touch ID in my code and this presentviewcontroller code was in completion. Raywenderlich handled completion with treads like this.
authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Testing Touch ID", reply: { (complete, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if complete {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("home") as! UITabBarController
self.presentViewController(vc, animated: true, completion: nil)
}
else{
}
})
})
I change my code like this and it worked fine. I edited my answer maybe this is a Xcode bug or else.
I am having various ViewControllers in my app. On one of them I want a alert to be displayed on load of the VC once to the user.
I have followed the instructions to set a glob var under the import section:
var disalert:Bool = true
and in the function I got:
if disalert {
let actionSheetController: UIAlertController = UIAlertController(title: "How-to use Holiday List", message: "message here", preferredStyle: .Alert)
//Create and add the Cancel action
//Create and an option action
let nextAction: UIAlertAction = UIAlertAction(title: "OK", style: .Default) { action -> Void in
}
actionSheetController.addAction(nextAction)
//Add a text field
//Present the AlertController
self.presentViewController(actionSheetController, animated: true, completion: nil)
disalert = false
}
The alert is not presented whilst the app is open. When I restart the phone or quit the app completely its again there.
Thank you!
If I am reading your question properly, my suggestion would be to user NSUserDefaults to save a key when the user first opens the view. Then just use an IF statement to decide whether an alertView should be displayed.
Before showing the alert, wherever you want to show it, check the value against the "disalert" key in your userDefaults with this statement:
var disalert: Bool = NSUserDefaults.standardUserDefaults.boolForKey("disalert");
if disalert {
// The alert has already been shown so no need to show it again
}
else
{
// The alert hasn't been shown yet. Show it now and save in the userDefaults
// After showing the alert write this line of code
NSUserDefaults.standardUserDefaults.setBool(true, forKey: "disalert")
}
Adeel's code worked for me, with a slight improvement:
var disalert: Bool =
NSUserDefaults.standardUserDefaults().boolForKey("disalert");
if disalert {
// The alert has already been shown so no need to show it again
}
else
{
// The alert hasn't been shown yet. Show it now and save in the userDefaults
// After showing the alert write this line of code
NSUserDefaults.standardUserDefaults.setBool(true, forKey: "disalert")
}
NSUserDefaults cried for the following: NSUserDefaults.standardUserDefaults()