user2836202
user2836202

Reputation: 639

Programmatic Device Specific iOS Constraint is nil

I came across an interesting problem that only arises on iPhone 6/6+ and iPad mini with retina display.

In the following code:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if(self.seeMoreContents)
    {
        BOOL isText = [self.seeMoreContents isText];
        self.imageView.hidden = isText;
        [self.textView removeConstraint:self.textHeightConstraint];
        [self.textWrapperView removeConstraint:self.textWrapperHeightConstraint];

        if (!isText)
        {
        __weak FCSeeMoreViewController *weakSelf = self;
            [self.imageView setImageByFlashcardSide:self.seeMoreContents completion:^(BOOL preloaded){
                weakSelf.imageView.center = CGPointMake(weakSelf.view.frame.size.width / 2, weakSelf.view.frame.size.height / 2);
                [weakSelf.scrollView setContentOffset:CGPointMake(0, 0)];
            }];
        }
    }
}


- (void)viewDidLayoutSubviews
{
    if ([self.seeMoreContents isText])
    {
        self.textView.text = self.seeMoreContents.text;
        self.textView.font = self.fontForContents;

        self.textWrapperView.hidden = NO;
        [self.textView sizeToFit];
        CGFloat height = self.textView.frame.size.height;
        [self updateView:self.textView withConstraint:self.textHeightConstraint ofValue:height];
        [self updateView:self.textWrapperView withConstraint:self.textWrapperHeightConstraint ofValue:height + self.wrapperMargin];

        [self.scrollView setContentSize:CGSizeMake(self.textView.frame.size.width, height + self.scrollTextMargin)];
        [self.scrollView setContentOffset:CGPointMake(0, -self.wrapperScrollVerticalConstraint.constant)];
    }
    [super viewDidLayoutSubviews];
}

- (void)updateView:(UIView*)view withConstraint:(NSLayoutConstraint*)constraint ofValue:(CGFloat)value
{
    constraint.constant = value;
    [view addConstraint:constraint];
}

By the time the two messages of udpateView get passed, the constraints have become nil. I could attribute this to weird garbage collection behavior, but it only happens on iPhone 6/6+ and mini retina iPad.

I have changed this whole controller to work better and to not to programmatically set constraints, but I want to know how/why this can happen on specific devices. Any insight would be greatly appreciated.

Upvotes: 1

Views: 146

Answers (1)

clearlight
clearlight

Reputation: 12615

Override this method in your UIViewController to detect changing of 'traits':

func willTransitionToTraitCollection(_ newCollection: UITraitCollection,
       withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) 

This is where you intercept constraint changes to get them at the right time, otherwise it's a race and your code can lose.

I suspect not using that function to get the timing right may be why you are not seeing consistent results. I bumped into the same kind of problem awhile back - not finding constraints that should have been there when I went looking for them.

Another thing to consider about mysterious constraints appearing and disappearing, of course, is UIView's

translatesAutoresizingMaskIntoConstraints

property, which if true (the default), causes iOS to dynamically create constraints, besides whatever you may have created programmatically or created in Interface Builder. And I have noticed some iOS generated constraints can disappear in different devices and orientations, as the iOS implementation that applies and removes such constraints is a black box.

Upvotes: 1

Related Questions