Sheet presentation resets constraints from storyboard

I am trying to switch constraints in my layout. In my project I use UIKit with storyboards. For some reason, in iOS 18 simulator, form sheet presentation resets constraints which were setup in my storyboard.
I have two constraints where one of them is not installed in the storyboard. When I swap isActive state in both constraints and open a sheet, the flags switch back to their original states.

import UIKit

class ViewController: UIViewController {
    @IBOutlet var redViewTopConstraint: NSLayoutConstraint?
    @IBOutlet var redViewBottomConstraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func openFormSheet() {
        let viewController = UIViewController()
        viewController.view.backgroundColor = .blue
        viewController.modalPresentationStyle = .formSheet
        present(viewController, animated: true)
    }

    @IBAction func toggleConstraints() {
        redViewTopConstraint?.isActive.toggle()
        redViewBottomConstraint?.isActive.toggle()
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23086.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina6_12" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23076"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Test_ios_18_bug" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="GhQ-n3-4eC">
                                <rect key="frame" x="91" y="423" width="211" height="31"/>
                                <subviews>
                                    <button opaque="NO" contentMode="scaleToFill" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lx5-r9-cxs">
                                        <rect key="frame" x="0.0" y="0.0" width="152" height="31"/>
                                        <state key="normal" title="Button"/>
                                        <buttonConfiguration key="configuration" style="plain" title="Open form sheet"/>
                                        <connections>
                                            <action selector="openFormSheet" destination="BYZ-38-t0r" eventType="touchUpInside" id="xne-NT-13P"/>
                                        </connections>
                                    </button>
                                    <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="WB7-FG-wMT">
                                        <rect key="frame" x="162" y="0.0" width="51" height="31"/>
                                        <connections>
                                            <action selector="toggleConstraints" destination="BYZ-38-t0r" eventType="valueChanged" id="X2V-rJ-gEt"/>
                                        </connections>
                                    </switch>
                                </subviews>
                            </stackView>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vfi-o4-jgR">
                                <rect key="frame" x="146.66666666666666" y="59" width="100" height="100"/>
                                <color key="backgroundColor" systemColor="systemRedColor"/>
                                <constraints>
                                    <constraint firstAttribute="width" constant="100" id="k3Q-RA-T6r"/>
                                    <constraint firstAttribute="height" constant="100" id="mvY-ej-r9M"/>
                                </constraints>
                            </view>
                        </subviews>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstItem="Vfi-o4-jgR" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="3IO-WP-fQ2"/>
                            <constraint firstItem="Vfi-o4-jgR" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="G1w-zW-l6a"/>
                            <constraint firstItem="GhQ-n3-4eC" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="RUe-tf-C1w"/>
                            <constraint firstItem="GhQ-n3-4eC" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="UDd-dC-W8D"/>
                            <constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="Vfi-o4-jgR" secondAttribute="bottom" id="w7S-f8-ghA"/>
                        </constraints>
                        <variation key="default">
                            <mask key="constraints">
                                <exclude reference="w7S-f8-ghA"/>
                            </mask>
                        </variation>
                    </view>
                    <connections>
                        <outlet property="redViewBottomConstraint" destination="w7S-f8-ghA" id="yug-ID-c0v"/>
                        <outlet property="redViewTopConstraint" destination="G1w-zW-l6a" id="uHZ-MY-ldM"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="697" y="77"/>
        </scene>
    </scenes>
    <resources>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
        <systemColor name="systemRedColor">
            <color red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </systemColor>
    </resources>
</document>
Initial state Swapped state State after presenting a sheet

If I use the constraints in code, I get the desired behavior:

import UIKit

class ViewController: UIViewController {
    var redViewTopConstraint: NSLayoutConstraint?
    var redViewBottomConstraint: NSLayoutConstraint?

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .orange

        let button = UIButton()
        button.setTitle("Open form sheet", for: .normal)
        button.addTarget(self, action: #selector(openFormSheet), for: .touchUpInside)

        let redView = UIView()
        redView.backgroundColor = .red
        redView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(redView)

        let redViewTopConstraint = redView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
        self.redViewTopConstraint = redViewTopConstraint

        redViewBottomConstraint = redView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)

        let toggle = UISwitch()
        toggle.addTarget(self, action: #selector(toggleConstraints), for: .valueChanged)

        let stackView = UIStackView(arrangedSubviews: [button, toggle])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.spacing = 10
        view.addSubview(stackView)

        NSLayoutConstraint.activate([
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            redView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            redView.widthAnchor.constraint(equalToConstant: 100),
            redView.heightAnchor.constraint(equalToConstant: 100),
            redViewTopConstraint
        ])
    }

    @objc func openFormSheet() {
        let viewController = UIViewController()
        viewController.view.backgroundColor = .blue
        viewController.modalPresentationStyle = .formSheet
        present(viewController, animated: true)
    }

    @objc func toggleConstraints() {
        redViewTopConstraint?.isActive.toggle()
        redViewBottomConstraint?.isActive.toggle()
    }
}

Is it a bug or documented behavior? Is there a parameter which prevent this to happen? Should I fix this or Apple will fix it when they release iOS 18?

I use Xcode 16 beta 3 and iOS 18.0 simulator.

Part of the problem here is that your code is wrong. If redViewTopConstraint is not active and redViewBottomConstraint is active, and you call toggleConstraints, you’re going to get an autolayout conflict, because for a moment both of them will be active at the same time. The code should read:

    if redViewTopConstraint?.isActive ?? false {
        redViewTopConstraint?.isActive.toggle()
        redViewBottomConstraint?.isActive.toggle()
    } else {
        redViewBottomConstraint?.isActive.toggle()
        redViewTopConstraint?.isActive.toggle()
    }

After that change, I couldn’t reproduce any issue using Xcode 15. If you test with Xcode 15 and you don’t get the issue but you do get it with Xcode 16 beta, please file a bug immediately, as this is just the sort of thing Apple wants to know about during this beta period.

Having said all that, I would also say that using the “Installed” checkbox to mean isActive seems to me to be a bit dicey. To be on the safe side, I would suggest adding these lines to your viewDidLoad:

    redViewBottomConstraint?.isActive = false
    redViewTopConstraint?.isActive = true

That way, you start life in a known state.

Trying to use constraints that have Installed un-checked in Storyboard has (from my experience) always been a hit-or-miss proposition.

I don’t have Xcode 16 beta 3 and iOS 18.0 simulator installed, but my assumption would be that something in the controller life-cycle has changed enough that the Storyboard settings are being re-applied.

Another option would be to keep both constraints installed, but manipulate their priorities instead.

Start with the bottom constraint set to Priority: Low (250) and change the toggle to this:

@IBAction func toggleConstraints() {
    //redViewTopConstraint?.isActive.toggle()
    //redViewBottomConstraint?.isActive.toggle()

    redViewTopConstraint?.priority = (redViewTopConstraint?.priority == .required) ? .defaultLow : .required
    redViewBottomConstraint?.priority = (redViewTopConstraint?.priority == .required) ? .defaultLow : .required
}

You’ll get warnings in the debug console because during that process there will be constraint conflicts. You can safely ignore those warnings.

To get rid of them, set the top constraint priority to 999 in Storyboard, and then use UILayoutPriority(999) (or .required - 1) instead of .required in code.

2

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật