Search code examples
iosnslayoutconstraintpresentviewcontroller

Presenting SKStoreProductViewController re-activates inactive constraint


I am presenting an SKStoreProductViewController, and getting some constraint conflicts. I can verify that a previously de-activated constraint is being re-activated. I can't see why this should happen.

See below, marked by *** ———> <———— *** for your reading convenience.

The only possible gotcha I can think of is this: my app is landscape-only, so I have to subclass SKStoreProductViewController.shouldAutorotate to return false.

class MyProductViewController : SKStoreProductViewController {
    override var shouldAutorotate: Bool {
        return false
    }
}

func openStoreProduct(identifier: String) {
    let storeViewController = MyProductViewController()
    storeViewController.delegate = self

    let parameters = [ SKStoreProductParameterITunesItemIdentifier : identifier]
    storeViewController.loadProduct(withParameters: parameters) { [weak self] (loaded, error)  in
        if loaded {
            print("In: \(self?.myConstraint.isActive)")
            // *** ———> Prints "In: false". <——— ***

            self?.present(storeViewController, animated: true) {
        }
    }
}

func productViewControllerDidFinish(_ viewController: SKStoreProductViewController) {
    print("Out: \(self.myConstraint.isActive)")
    // *** ———> prints "Out: true" <——— ***

    viewController.dismiss(animated: true, completion: nil)
}

Solution

  • The problem is that when returning from presenting the StoreProduct controller, some layout values have been restored to their IB values, losing values set programmatically, e.g. isHidden, isActive, etc.

    In this case, I was replacing constraints in certain situations, but leaving the original IB one active when no change was needed. Upon return from the Store, the original constraints were re-activated, but their replacements were also still active. Of course they conflicted.

    The solution is to un-check the constraint's "Installed" checkbox in IB, and replace (and activate) the constraint in code for every desired case. Rather than leaving it untouched when you don't want to change it.

    For other UI things that may get messed up, you can set a flag in productViewControllerDidFinish() and test for it in your layout code.

    This behavior may be related to the landscape issue mentioned in the question. On iPhone, the StoreProductViewController presents only in portrait mode. When the app is in landscape, and the current ViewController presents the StoreProduct one, the OS apparently force-rotates the app to portrait, before presenting the Store. You can see this happen briefly. (This is not an issue on iPad, because the Store presents as a popover, in either orientation.)