iOS 8.3 UIAlertController crashes when trying to add a textfield

后端 未结 12 1557
暗喜
暗喜 2020-12-30 03:44

I have an iPad app. I am creating an UIAlertController and adding a textfield. It crashes. It only crashes when I add a textfield.

let alert = UIAlertContr         


        
相关标签:
12条回答
  • 2020-12-30 04:15

    This bug is triggered if the UIAlertController's view is loaded when you calling -addTextFieldWithConfigurationHandler: ([alert isViewLoaded] == YES).

    If you are accessing alert.view prior to calling -addTextFieldWithConfigurationHandler, move whatever you are doing with alert.view to after the call to -addTextFieldWithConfigurationHandler:.

    0 讨论(0)
  • 2020-12-30 04:18

    I just ran your code inside my test project — everything worked fine on 8.3.

    View not found in container hierarchy:

    This error usually appears if you mess up UIViewController child/parent relationship. There are few points to consider:

    • the controller you are using to present alert is topmost and is not presenting anything else already
    • parent controllers either have the one you use as a child (addChildViewController:) or are in a state of presenting it through either presentViewController:animated:completion: or the likes of it
    • controller's view is loaded before presenting another ViewController

    Also, there is definitely something wrong with the frames.

    0 讨论(0)
  • 2020-12-30 04:18

    I had a similair problem that is also mentioned in the comments. Please see this if you are getting.

    *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The layout constraints still need update after sending -updateConstraints to <_UIKeyboardLayoutAlignmentView: 0x792d28e0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = >. _UIKeyboardLayoutAlignmentView or one of its superclasses may have overridden -updateConstraints without calling super. Or, something may have dirtied layout constraints in the middle of updating them. Both are programming errors.'

    NSInteralInconsistencyException - UIKeyboardLayoutAlignmentView

    0 讨论(0)
  • 2020-12-30 04:25

    I have the same problem with the new iOS 8.3 and Swift 1.2. UIAlertController in UIViewController with nested UITableView does not work as in start topic.

    So, I made a real modal form.

    1. Create new UIViewController width, set views background to black with 0.4 opacity
    2. Add a 300x150 UIView with two buttons, label and UITextField
    3. Add constraints and other needed staff You must see something like this
    4. Connect modally other controllers with the new one enter image description here
    5. And specify special class for new controller as "PopupWindow". Then create this class:

      import UIKit
      
      class PopupWindow: UIViewController, UITextFieldDelegate {
      
          @IBOutlet var wrapper: UIView!
          @IBOutlet var btnCancel: UIButton!
          @IBOutlet var btnSave: UIButton!
          @IBOutlet var textField: UITextField!
          @IBOutlet var labelField: UILabel!
      
          var keyboardHeight: CGFloat = 0
          var data = [:]
          var closure: ((textField: UITextField!) -> Void)?
          var tmpText = ""
      
          override func viewDidLoad() {
              super.viewDidLoad()
      
              self.labelField.text = self.data["title"] as? String
              self.textField.text = self.data["text"] as? String
      
              self.btnCancel.setTitle("cancel", forState: UIControlState.Normal)
              var tmp = self.data["save"] != nil
                  ? self.data["save"] as! String
                  : "save"
              self.btnSave.setTitle(tmp, forState: UIControlState.Normal)
              self.btnSave.enabled = false
      
              self.wrapper.layer.cornerRadius = 5.0 as CGFloat
              self.textField.becomeFirstResponder()
          }
      
          @IBAction func onBtnCancel() {
              self.dismissViewControllerAnimated(true, completion: nil)
          }
      
          @IBAction func onBtnSave() {
              if self.closure != nil {
                  self.dismissViewControllerAnimated(true, completion: {
                      _ in
                      self.closure!(textField: self.textField)
                  })
              }
      
          }
      
          override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
              self.fixTopOffset()
          }
      
          override func viewWillAppear(animated: Bool) {
              super.viewWillAppear(animated)
      
              NSNotificationCenter.defaultCenter().addObserver(self, selector: "textFieldDidChange:", name: UITextFieldTextDidChangeNotification, object: self.textField)
      
              NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboadWillShow:", name: UIKeyboardWillShowNotification, object: nil)
              NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboadWillShow:", name: UIKeyboardWillChangeFrameNotification, object: nil)
              NSNotificationCenter.defaultCenter().addObserver(self, selector: "onKeyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
          }
      
          override func viewWillDisappear(animated: Bool) {
              super.viewWillDisappear(animated)
      
              NSNotificationCenter.defaultCenter().removeObserver(self, name: UITextFieldTextDidChangeNotification, object: nil)
      
              NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
              NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillChangeFrameNotification, object: nil)
              NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
          }
      
          func onKeyboadWillShow(notification: NSNotification) {
              self.fixTopOffset()
              let info: NSDictionary = notification.userInfo!
              if let rectValue = info[UIKeyboardFrameBeginUserInfoKey] as? NSValue {
                  let kbSize: CGRect = rectValue.CGRectValue()
                  if self.keyboardHeight != kbSize.size.height {
                      self.keyboardHeight = kbSize.size.height
                      self.fixTopOffset()
                  }
              }
          }
      
          func onKeyboardWillHide(notification: NSNotification) {
              self.fixTopOffset()
              if self.keyboardHeight != 0 {
                  self.keyboardHeight = 0
                  self.fixTopOffset()
              }
          }
      
          func fixTopOffset(landscape: Bool = true) {
              let height1: CGFloat = self.view.frame.height / 2
              let height2: CGFloat = height1 - self.keyboardHeight / 2
              let margin: CGFloat = height1 - height2
              for tmp in self.view.constraints() {
                  if let constraint = tmp as? NSLayoutConstraint {
                      if constraint.firstAttribute == NSLayoutAttribute.CenterY {
                          if constraint.constant != margin {
                              constraint.constant = margin
                          }
                      }
                  }
      
              }
          }
      
          func textFieldDidChange(notification: NSNotification) {
              if notification.object != nil {
                  if let textField = notification.object as? UITextField {
                      self.btnSave.enabled = textField.text != self.tmpText
                  }
              }
          }
      
      }
      

    You need to connect all IBOutlets with corresponding elements in view by Ctrl+Drag.

    1. And now you can use it window in any connected controller. For example:

      import UIKit
      
      class ExampleView: UIViewController {
      
          override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {       
              if segue.identifier == "showPopup" {
                  if let controller = segue.destinationViewController as? PopupWindow {
                      controller.data = sender as! NSDictionary
                      // This action will be called after form submission
                      // We just print text in console
                      controller.closure = {
                          (textField: UITextField!) in
                          println(textField)
                      }
                  }
              }
          }
      
          func showPopupWindow() {
              let data = [
                      "title": "My Window",
                      "save": "Save",
                      "text": "Do you realy want to save this text?",
              ]
              self.performSegueWithIdentifier("showPopup", sender: data)
          }
      }
      

    Now I can just add a segue to controller and write any closure in prepareSegue method - and it works!

    I made short video with popup window in my app - http://youtu.be/JmqAAeUN-XU

    0 讨论(0)
  • 2020-12-30 04:26

    Edit: This fix changes depending on if you are building with Xcode 6 or Xcode 7, so I've added the relevant information for both versions of Xcode.


    I ran into this today and what it's saying is that it can't add the text field to the view controller's view or that it can't add auto-layout constraints to its superview. This seems to be because it hasn't created the superview to add it to yet, and so it all panics and crashes.

    Simple fix I found is add the text field after you tell the alert controller to present. That fixed it to me, though I'm not sure if it'll affect anything like the text field popping in as the alert is presenting.

    Built with Xcode 6

    let alertController = UIAlertController(title: "Enter Name", message:nil, preferredStyle: .Alert)
    
    let okAction = UIAlertAction(title: "Ok", style: .Default) { (_) -> Void in
        // Some action here
    }
    alertController.addAction(okAction)
    
    presentViewController(alertController, animated: true, completion: nil)
    
    // Add any text fields after presenting the alert controller to fix crash in iOS 8.3
    alertController.addTextFieldWithConfigurationHandler { (textfield) -> Void in
        textfield.placeholder = "Name"
    }
    

    P.s. As a side note from your code example, remember with Swift, you don't need to use ; at the end of every line, though it doesn't matter if you do.

    0 讨论(0)
  • 2020-12-30 04:28

    Try to set alert.view.frame explicitly to something small. I think by default it may be as big as the application view, triggering this on its subviews.

    0 讨论(0)
提交回复
热议问题