swiftuicollectionviewuicollectionviewlayout

UIAlertController conflicts with UICollectionViewFlowLayout


I have a strange problem, where my extension of UICollectionViewFlowLayout conflicts with a UIAlertController, and removes its button.

My app has a uicollectionviewcontroller with paging enabled, and my uicollectionviewflowlayout extension makes sure a single cell fills the whole screen

// Extension to make a UICollectionViewCell fill the whole screen
extension UICollectionViewFlowLayout {
  public override func prepareLayout() {
    let ratio : CGFloat = 5.6 / 8.7
    
    let cardHeight = collectionView!.frame.height * 0.7
    let cardWidth = cardHeight * ratio
    let spacing = (collectionView!.frame.height - cardHeight) / 2
    
    itemSize = CGSize(width: cardWidth, height: cardHeight)
    minimumLineSpacing = spacing*2
    sectionInset = UIEdgeInsets(top: spacing, left: 0, bottom: spacing, right: 0)
  }
}

And whenever I call a UIAlertController

let alertController = UIAlertController(title: "Error", message: "Error", preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "OK", style: .Cancel) { (action) in })
self.presentViewController(alertController, animated: true) {}

I get the following message in the console

2016-01-01 21:04:48.924 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c4e80 h=--& v=--& H:[_UIAlertControllerActionView:0x15f53d9e0(19.8253)]>",
    "<NSLayoutConstraint:0x15f67b370 H:|-(>=12)-[UIView:0x15f53e0c0]   (Names: '|':_UIAlertControllerActionView:0x15f53d9e0 )>",
    "<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-01-01 21:04:48.926 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c62a0 h=--& v=--& V:[_UIAlertControllerActionView:0x15f53d9e0(30.8)]>",
    "<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-01-01 21:04:48.927 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c4e80 h=--& v=--& H:[_UIAlertControllerActionView:0x15f53d9e0(19.8253)]>",
    "<NSLayoutConstraint:0x15f67b370 H:|-(>=12)-[UIView:0x15f53e0c0]   (Names: '|':_UIAlertControllerActionView:0x15f53d9e0 )>",
    "<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-01-01 21:04:48.927 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c62a0 h=--& v=--& V:[_UIAlertControllerActionView:0x15f53d9e0(30.8)]>",
    "<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-01-01 21:04:48.938 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c4e80 h=--& v=--& H:[_UIAlertControllerActionView:0x15f53d9e0(19.8253)]>",
    "<NSLayoutConstraint:0x15f67b370 H:|-(>=12)-[UIView:0x15f53e0c0]   (Names: '|':_UIAlertControllerActionView:0x15f53d9e0 )>",
    "<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67b3c0 UIView:0x15f53e0c0.trailing <= _UIAlertControllerActionView:0x15f53d9e0.trailing - 12>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-01-01 21:04:48.940 Jeg Har Aldrig[10912:3649777] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
    (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x15f6c62a0 h=--& v=--& V:[_UIAlertControllerActionView:0x15f53d9e0(30.8)]>",
    "<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15f67bd50 V:[_UIAlertControllerActionView:0x15f53d9e0(>=44)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

While the button on my UIAlertControllers don't appear, see the image enter image description here

Any suggestiens?

Solution based on Mattvens answer

Instead of making an extension I made a subclass:

class FullCellLayout: UICollectionViewFlowLayout {
  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    
    let ratio : CGFloat = 5.6 / 8.7
    
    let cardHeight = UIScreen.mainScreen().bounds.height * 0.7
    let cardWidth = cardHeight * ratio
    let spacing = (UIScreen.mainScreen().bounds.height - cardHeight) / 2
    
    itemSize = CGSize(width: cardWidth, height: cardHeight)
    minimumLineSpacing = spacing*2
    sectionInset = UIEdgeInsets(top: spacing, left: 0, bottom: spacing, right: 0)
  }
}

Solution

  • Short answer: Don't use an extension for this.

    Extensions in Swift are global, so your extension to UICollectionViewLayout is affecting all UICollectionViewLayout classes.

    Judging from the error you are getting, UIAlertController is internally using UICollectionView to layout buttons, and your extension is breaking that functionality.

    You should use a subclass, if you really need it, but there's no reason (that I know of) you can't initialize UICollectionViewFlowLayout, assign it to a var and use that.