16

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 = UIAlertController(title: "Enter Name", message:nil, preferredStyle: UIAlertControllerStyle.Alert);         
alert.addTextFieldWithConfigurationHandler { (textfield:UITextField!) -> Void in
                textfield.placeholder = "Sexy time";

            }
 alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: {(action:UIAlertAction!) -> Void in
      //Some action here   
 }));

 self.presentViewController(alert, animated: true, completion: nil);

I get a fun crash telling me that the constraints are messed up. This code works fine in < 8.3 with no warnings. Even on a clean project with nothing in it but this code, it crashes - The project needs to be a splitview project on iPad.

Here is the full stack trace plus bizarre constraint warnings which appears only after trying to add the textfield to alertController.

2015-04-10 15:25:07.155 Observation[18235:281813] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fb66cf9dfc0 UITableView:0x7fb66b855000.left == UIView:0x7fb66fae68e0.left>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2015-04-10 15:25:07.155 Observation[18235:281813] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fb66cf9e010 UITableView:0x7fb66b855000.right == UIView:0x7fb66fae68e0.right>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2015-04-10 15:25:07.155 Observation[18235:281813] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fb66fb37f90 UITableView:0x7fb66b855000.top == UIView:0x7fb66fae68e0.top>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2015-04-10 15:25:07.156 Observation[18235:281813] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7fb66fb80580 UITableView:0x7fb66b855000.bottom == UIView:0x7fb66fae68e0.bottom>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2015-04-10 15:25:13.589 Observation[18235:281813] View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0x7fb66cf9dfc0 UITableView:0x7fb66b855000.left == UIView:0x7fb66fae68e0.left>
    Container hierarchy: 
<UIView: 0x7fb66fa86e00; frame = (0 0; 0 0); layer = <CALayer: 0x7fb66fadf8e0>>
   | <UIView: 0x7fb66af3e080; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0x7fb66fae32c0>>
   |    | <_UIAlertControllerShadowedScrollView: 0x7fb66fa68c80; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fb66fa38a80>; layer = <CALayer: 0x7fb66fa97560>; contentOffset: {0, 0}; contentSize: {0, 0}>
   |    |    | <UIView: 0x7fb66fa87350; frame = (0 0; 0 0); layer = <CALayer: 0x7fb66fadf810>>
   |    |    |    | <UILabel: 0x7fb66fa88740; frame = (0 0; 0 0); text = 'Enter Name'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fb66fa94ed0>>
   |    |    |    | <UILabel: 0x7fb66fa73710; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fb66cc0ee10>>
   |    |    |    | <UIView: 0x7fb66fae68e0; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0x7fb66fa90160>>
   |    | <UILabel: 0x7fb66fa3ad40; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fb66fa73680>>
   |    | <UICollectionView: 0x7fb66c130200; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x7fb66faebab0>; layer = <CALayer: 0x7fb66fa3acf0>; contentOffset: {0, 0}; contentSize: {0, 0}> collection view layout: <_UIAlertControllerCollectionViewFlowLayout: 0x7fb66fae0b30>
    View not found in container hierarchy: <UITableView: 0x7fb66b855000; frame = (0 20; 768 1004); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fb66cf79f30>; layer = <CALayer: 0x7fb66cf600a0>; contentOffset: {0, 0}; contentSize: {768, 25}>
    That view's superview: NO SUPERVIEW
2015-04-10 15:25:13.594 Observation[18235:281813] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view.  Does the constraint reference something from outside the subtree of the view?  That's illegal. constraint:<NSLayoutConstraint:0x7fb66cf9dfc0 UITableView:0x7fb66b855000.left == UIView:0x7fb66fae68e0.left> view:<UIView: 0x7fb66fa86e00; frame = (0 0; 0 0); layer = <CALayer: 0x7fb66fadf8e0>>'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000102940c65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010221dbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x0000000102940b9d +[NSException raise:format:] + 205
    3   Foundation                          0x0000000101daf479 -[NSLayoutConstraint _addToEngine:integralizationAdjustment:mutuallyExclusiveConstraints:] + 187
    4   UIKit                               0x00000001039bca34 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 474
    5   Foundation                          0x0000000101dbd1be -[NSISEngine withBehaviors:performModifications:] + 155
    6   UIKit                               0x00000001039bc83a __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
    7   UIKit                               0x00000001039bc64d -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
    8   UIKit                               0x00000001039bc933 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
    9   Foundation                          0x0000000101dbd1be -[NSISEngine withBehaviors:performModifications:] + 155
    10  UIKit                               0x00000001039bc83a __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
    11  UIKit                               0x00000001039bc64d -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
    12  UIKit                               0x00000001039bc933 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
    13  Foundation                          0x0000000101dbd1be -[NSISEngine withBehaviors:performModifications:] + 155
    14  UIKit                               0x00000001039bc83a __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
    15  UIKit                               0x00000001039bc64d -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
    16  UIKit                               0x00000001033b5717 __40-[UIView(Hierarchy) layoutBelowIfNeeded]_block_invoke + 39
    17  Foundation                          0x0000000101dbd1be -[NSISEngine withBehaviors:performModifications:] + 155
    18  UIKit                               0x00000001033b5556 -[UIView(Hierarchy) layoutBelowIfNeeded] + 320
    19  UIKit                               0x000000010374a394 -[_UIAlertControllerAnimatedTransitioning animateTransition:] + 470
    20  UIKit                               0x000000010344fa4e __56-[UIPresentationController runTransitionForCurrentState]_block_invoke + 1867
    21  UIKit                               0x000000010336562c _applyBlockToCFArrayCopiedToStack + 314
    22  UIKit                               0x00000001033654a6 _afterCACommitHandler + 533
    23  CoreFoundation                      0x0000000102873ca7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    24  CoreFoundation                      0x0000000102873c00 __CFRunLoopDoObservers + 368
    25  CoreFoundation                      0x0000000102869a33 __CFRunLoopRun + 1123
    26  CoreFoundation                      0x0000000102869366 CFRunLoopRunSpecific + 470
    27  GraphicsServices                    0x0000000106dd6a3e GSEventRunModal + 161
    28  UIKit                               0x0000000103341900 UIApplicationMain + 1282
    29  Observation                         0x0000000101612927 main + 135
    30  libdyld.dylib                       0x0000000104f60145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
MweyaMutsvene
  • 543
  • 4
  • 15

12 Answers12

13

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.


Built with Xcode 7

When you build your app using Xcode 7, it seems like Apple have fixed the issue. Using the method shown above will no longer show a text field in iOS 9 (even though it still shows correctly in iOS 8).

Below is a snippet of code, how it should have been the whole time, and when built in Xcode 7 it runs correctly in iOS 8 and iOS 9.

let alertController = UIAlertController(title: "Enter Name", message:nil, preferredStyle: .Alert)

alertController.addTextFieldWithConfigurationHandler { (textfield) -> Void in
    textfield.placeholder = "Name"
}

let okAction = UIAlertAction(title: "Ok", style: .Default) { (_) -> Void in
    // Some action here
}
alertController.addAction(okAction)

presentViewController(alertController, animated: true, completion: nil)

Tested in Swift 2.0 and Obj-C with Xcode 7 GM (7A218)

Baza207
  • 2,123
  • 1
  • 22
  • 40
  • Awesome, thanks, worked perfectly. And yes I do know I dont need to use the ";", it just feels incomplete if I dont :) – MweyaMutsvene Apr 28 '15 at 18:13
  • 1
    This workaround fixes the crash on iOS 8.3 and 8.4. However, take note that as of iOS 9 beta 1 through 3, this results in an alert controller **without** the text field. Thus, this workaround should only be applied for iOS 8.x. – junjie Jul 21 '15 at 00:49
  • I can confirm that in the current iOS 9 Beta built in Xcode 7 Beta 3, this fix doesn't work. As @junjie points out, it just doesn't add a text field. I'll update the answer when the GM versions of Xcode 7 and iOS 9 are released. – Baza207 Jul 21 '15 at 09:52
6

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:.

Dex
  • 871
  • 4
  • 4
4

As @Dex mentioned, I fixed this by modifying my controller's view AFTER adding the text field. I was modifying the view's tint color.

controller.view.tintColor = ...some color...

Moving this to "after" adding the text field fixed it for me. Accepted answer and other suggestions led to other bugs for me. Sorry, I don't have the rep to post a comment yet on @Dex's answer.

BigShay
  • 41
  • 6
3

This seems to have something to do with styling the UIAlertController's view, as eluded to by @BigShay.

In my example I set the tintColor of the view before adding the UITextField and I crash in iOS 8. The workaround given by @Baza207 to add the UITextField after displaying the alert avoids the crash in iOS 8, however it also results in no text field appearing at all in iOS 9.

If you just move the styling to after adding the text field, it works with both iOS 8 and iOS 9 (no crash in iOS 8, and no missing text field in iOS 9):

Crash in iOS 8

Works in iOS 9

alertController.view.tintColor = UIColor.blueColor()

alertController.addTextFieldWithConfigurationHandler { textField in
}

presentViewController(alertController, animated: true, completion: nil)

Works in iOS 8

No text text field in iOS 9

alertController.view.tintColor = UIColor.blueColor()

presentViewController(alertController, animated: true, completion: nil)

alertController.addTextFieldWithConfigurationHandler { textField in
}

Works in iOS 8

Works in iOS 9

alertController.addTextFieldWithConfigurationHandler { textField in
}

alertController.view.tintColor = UIColor.blueColor()

presentViewController(alertController, animated: true, completion: nil)
Michael Peterson
  • 10,383
  • 3
  • 54
  • 51
2

There does seem to a bug in iOS 8.3 related alerts. It manifests on both (deprecated) UIAlertView and the iOS8-only UIAlertController. When I attempt to add a textfield to either of these controllers, I get the following crash:

 *** 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 = <CALayer: 0x792d2ab0>>.
_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.'

Alerts without textfields are OK, but showing a UIAlertView with style UIAlertViewStylePlainTextInput or showing a UIAlertController with a textfield added via addTextFieldWithConfigurationHandler will result in the above crash.

The fix seems to be to set a prophylactic frame on the UIAlertController before calling show. This frame is overridden before show, but prevents the crash.

if (NSClassFromString(@"UIAlertController")) {
    // iOS8
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert"
                                                                   message:@"Be alert, not alarmed"
                                                            preferredStyle:UIAlertControllerStyleAlert];
    [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
        textField.keyboardType = UIKeyboardTypeEmailAddress;

    }];
    alert.view.frame = CGRectMake(0.0, 0.0, 320.0, 400.0); // Workaround iOS8.3 bug - set this to larger than you'll need

    [self presentViewController:alert animated:YES completion:^{
        [alert.textFields[0] becomeFirstResponder];
    }];
} else {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert"
                                                    message:@"Be alert, not alarmed"
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    alert.alertViewStyle = UIAlertViewStylePlainTextInput;
    UITextField *emailField = [alert textFieldAtIndex:0];
    emailField.keyboardType = UIKeyboardTypeEmailAddress;

    [alert show];
}
exidy
  • 241
  • 2
  • 4
  • I was extremely hopeful that this would work for me, but unfortunately it didn't – MweyaMutsvene Apr 13 '15 at 14:36
  • Please see my answer below, I had the same crash and fixed it. – Chris Apr 15 '15 at 12:27
  • See my answer as well on this page, fixed immediately. Had the same NSInternalInconsistencyException problem. – Michael Apr 17 '15 at 00:53
  • Other way that worked for me - if you want to continue using UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" -> prior to show call [self.view endEditing:YES]; However I recommend moving to AlertController – Nikolay DS May 11 '15 at 19:06
1

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.

morpheby
  • 11
  • 2
  • I forgot to mention that the project needs to be a splitviewcontroller on ipad. Happens when I add the code to the ViewDidAppear method in the default DetailViewController that xcode creates for you – MweyaMutsvene Apr 13 '15 at 14:38
1

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

Community
  • 1
  • 1
Chris
  • 1,637
  • 1
  • 14
  • 20
0

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.

Shazron
  • 2,446
  • 1
  • 18
  • 30
0

Aha, I think this may be answered by jcesarmobile in another thread: UIAlertController/UIAlertView scrolling on iOS 8

The workaround a lot of folks added to deal with prior bugs with long text in UIAlertController now causes this crash in 8.3. And the long text issue is fixed in 8.3, so the workaround can be made conditional to avoid this in 8.3

Community
  • 1
  • 1
chrbal
  • 3
  • 2
0

This fixed it immediately (for me). I had the exact same error that Chris described :

NSInteralInconsistencyException - UIKeyboardLayoutAlignmentView

The answer was simply to make sure animated is set to "NO" when presenting the UIAlertController.

[self presentViewController:alert animated:NO completion:nil];
Community
  • 1
  • 1
Michael
  • 3,269
  • 2
  • 23
  • 16
  • This may work when the problem is the UIKeyboardLayoutAlignmentView, but if the stack trace is as per this question, the crash occurs when the text field is added to the alert, before `presentViewController` is even called. Baza's answer resolves this. – tobygriffin Apr 17 '15 at 04:35
  • In my app this did not work for me but the fix in my link did. Guess its one of those weird ones. Re: it bring a different fix to original question, yes we know, but as some people were asking about that crash as well in this topic. So it best to link. – Chris Apr 17 '15 at 06:04
  • Yes, and thanks to everyone for clarifying this distinction for future viewers. – Michael Apr 17 '15 at 21:07
0

I really didn't like the solutions I saw and came up with an easier one. The crash occurs (for me, at least) when the keyboard is visible and an alert with an input field is presented.

I simply dismiss the keyboard prior to presenting the alert and then everything is fine.

Matt Koala
  • 2,171
  • 2
  • 18
  • 14
-1

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

bezumkin
  • 59
  • 4
  • 1
    Recreating a UIAlertController seems a very long winded way of fixing an issue like this. As a general rule recreation should be the last resort, and if you want added functionality, then subclassing or extensions should be used. – Baza207 Apr 16 '15 at 16:59