Objective c iOS 8键盘扩展:出现呼叫栏时出现约束错误?

Objective c iOS 8键盘扩展:出现呼叫栏时出现约束错误?,objective-c,ios8,autolayout,nslayoutconstraint,custom-keyboard,Objective C,Ios8,Autolayout,Nslayoutconstraint,Custom Keyboard,我注意到,当我在打电话时,绿色的呼叫栏出现在屏幕顶部,我的自定义键盘就不会出现(就好像被跳过了一样)。所以我调试了它,发现它是一个约束错误 以下是调试器中的错误: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The layout constraints still need update after sending -updateViewConstraints

我注意到,当我在打电话时,绿色的呼叫栏出现在屏幕顶部,我的自定义键盘就不会出现(就好像被跳过了一样)。所以我调试了它,发现它是一个约束错误

以下是调试器中的错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The layout constraints still need update after sending -updateViewConstraints to <KeyboardViewController: 0x16dfbe30>.
KeyboardViewController or one of its superclasses may have overridden -updateViewConstraints without calling super or sending -updateConstraints to the view. Or, something may have dirtied layout constraints in the middle of updating them.  Both are programming errors.'
*** First throw call stack:
(0x2ab43c1f 0x382eec8b 0x2ab43b65 0x2e6300ef 0x2b7cb5b9 0x2e630203 0x2e0ef4e9 0x2b7cb5b9 0x2e0ef2c3 0x2e630487 0x2e29ba8b 0x2e0004d7 0x2da28a0d 0x2da243e5 0x2da2426d 0x2da23c51 0x2da23a55 0x2dff8965 0x2ab0a3b5 0x2ab07a73 0x2ab07e7b 0x2aa56211 0x2aa56023 0x31e4f0a9 0x2e0621d1 0x389cf9fb 0x389d1021 0x2b916635 0x33956065 0x33955d3b 0x33956099 0x37c7a4fd 0x3886eaaf)
libc++abi.dylib: terminating with uncaught exception of type NSException
**注意:WIDTH()和HEIGHT()是宏

我在xib中使用自动布局。我不知道从哪里开始解决这个问题

更新 感谢您帮助调试这个@Remus!我现在试图检测设备何时在iOS 8上的扩展内旋转,但我的updateConstraints方法仍然没有被调用

- (void)viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];
    [self.view setNeedsLayout];
    [self.view updateConstraintsIfNeeded];
    //I've also tried [self.view updateConstraints]; instead
}

- (void)updateConstraints {

    NSLog(@"Check Width");
    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) {return;}

    NSLog(@"Remove Old Constraints");
    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    NSLog(@"Define Landscape");
    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    NSLog(@"Update view height depending on orientation.");
    //Update view height depending on orientation
    if (self.isLandscape) {
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    } else {
        NSLog(@"Detected in portrait.");
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    }
}

- (void)viewWillAppear:(BOOL)animated {

    NSLog(@"View Did Appear: Add Constraint.");
    [self.view updateConstraints];

    //Update our keyboard's height when view appears
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                         attribute:NSLayoutAttributeHeight
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:0.0
                                                          constant:self.portraitHeight];
    self.heightConstraint.priority = 990;
    [self.view addConstraint:self.heightConstraint];
}
-(void)ViewDidLayoutSubView{
[超级视图布局子视图];
[self.view setNeedsLayout];
[self.view updateConstraintsIfNeeded];
//我还尝试了[self.view updateConstraints];相反
}
-(void)updateConstraints{
NSLog(“检查宽度”);
//检查self.view是否存在
如果(宽度(self.view)==0 | |高度(self.view)==0){return;}
NSLog(@“删除旧约束”);
//删除以前的任何约束
[self.inputView removeConstraint:self.heightConstraint];
NSLog(“定义景观”);
//定义景观模式
self.isLandscape=!(self.view.frame.size.width==([[UIScreen mainScreen]边界].size.width*([[UIScreen mainScreen]边界].size.width<[UIScreen mainScreen]边界]+([UIScreen mainScreen]边界].size.width>[UIScreen mainScreen]边界].size.height])+([UIScreen mainScreen]边界].size.height*);
NSLog(@“根据方向更新视图高度”);
//根据方向更新视图高度
if(self.isLandscape){
//重新调整键盘的高度
self.heightConstraint.constant=self.landscapeHeight;
[self.inputView addConstraint:self.heightConstraint];
self.view.frame=CGRectMake(0,0,宽度(self.view),高度(self.view));
}否则{
NSLog(@“在纵向中检测到”);
//重新调整键盘的高度
self.heightConstraint.constant=self.height;
self.heightConstraint.priority=990;
[self.inputView addConstraint:self.heightConstraint];
self.view.frame=CGRectMake(0,0,宽度(self.view),高度(self.view));
}
}
-(无效)视图将显示:(BOOL)动画{
NSLog(@“视图确实出现:添加约束。”);
[self.view updateConstraints];
//显示视图时更新键盘的高度
self.heightConstraint=[NSLayoutConstraint constraintWithItem:self.view
属性:NSLayoutAttributeHeight
关系人:NSLayoutRelationEqual
toItem:无
属性:nsLayoutAttribute属性
乘数:0.0
常数:自画像高度];
self.heightConstraint.priority=990;
[self.view addConstraint:self.heightConstraint];
}

让我们尝试调用
viewdilayoutsubview
中的函数。这也可以在任何其他约束事件(如
updateViewConstraints
等)内单独调用

-(void)ViewDidLayoutSubView{
[超级视图布局子视图];
[自我设置键盘约束];
}
-(void)设置键盘约束{
NSLog(“检查宽度”);
//检查self.view是否存在
如果(宽度(self.view)==0 | |高度(self.view)==0){return;}
NSLog(@“删除旧约束”);
//删除以前的任何约束
[self.inputView removeConstraint:self.heightConstraint];
NSLog(“定义景观”);
//定义景观模式
self.isLandscape=!(self.view.frame.size.width==([[UIScreen mainScreen]边界].size.width*([[UIScreen mainScreen]边界].size.width<[UIScreen mainScreen]边界]+([UIScreen mainScreen]边界].size.width>[UIScreen mainScreen]边界].size.height])+([UIScreen mainScreen]边界].size.height*);
NSLog(@“根据方向更新视图高度”);
//根据方向更新视图高度
if(self.isLandscape){
//重新调整键盘的高度
self.heightConstraint.constant=self.landscapeHeight;
[self.inputView addConstraint:self.heightConstraint];
self.view.frame=CGRectMake(0,0,宽度(self.view),高度(self.view));
}否则{
NSLog(@“在纵向中检测到”);
//重新调整键盘的高度
self.heightConstraint.constant=self.height;
self.heightConstraint.priority=990;
[self.inputView addConstraint:self.heightConstraint];
self.view.frame=CGRectMake(0,0,宽度(self.view),高度(self.view));
}
}

我认为您在重写
updateViewConstraints
的过程中肯定发生了一些事情。您是否在该方法中放置了断点以找出哪一行实际触发了约束失败?哎呀!好主意,让我们试试吧!好吧,这很奇怪。显然,
updateViewConstraints
被调用了3次。在第一个过程中,它假定默认高度为216,在第二个过程中,它调整所有内容,在第三个过程中,它加载最后一行(即使它在第二个空间中分配了空间)。奇怪的是,当我设置断点时,一切正常。那么,也许这与时间有关?也许顶部栏的约束会干扰我键盘上的默认约束?可能。。如果您尝试在
updateConstraints
中调用这些函数而不是
updateViewConstraints
,会怎么样?谢谢Remus,但我似乎找不到
updateConstraints
的方法调用。嗯…谢谢你的帮助,雷姆斯!所以我尝试了以下(更新了我的答案)但是
- (void)viewWillAppear:(BOOL)animated {

    //Update our keyboard's height when view appears
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                         attribute:NSLayoutAttributeHeight
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:0.0
                                                          constant:self.portraitHeight];
    self.heightConstraint.priority = 990;
    [self.view addConstraint:self.heightConstraint];
}
- (void)viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];
    [self.view setNeedsLayout];
    [self.view updateConstraintsIfNeeded];
    //I've also tried [self.view updateConstraints]; instead
}

- (void)updateConstraints {

    NSLog(@"Check Width");
    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) {return;}

    NSLog(@"Remove Old Constraints");
    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    NSLog(@"Define Landscape");
    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    NSLog(@"Update view height depending on orientation.");
    //Update view height depending on orientation
    if (self.isLandscape) {
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    } else {
        NSLog(@"Detected in portrait.");
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    }
}

- (void)viewWillAppear:(BOOL)animated {

    NSLog(@"View Did Appear: Add Constraint.");
    [self.view updateConstraints];

    //Update our keyboard's height when view appears
    self.heightConstraint = [NSLayoutConstraint constraintWithItem:self.view
                                                         attribute:NSLayoutAttributeHeight
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:nil
                                                         attribute:NSLayoutAttributeNotAnAttribute
                                                        multiplier:0.0
                                                          constant:self.portraitHeight];
    self.heightConstraint.priority = 990;
    [self.view addConstraint:self.heightConstraint];
}
- (void)viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];
    [self setKeyboardConstraints];
}

- (void)setKeyboardConstraints {

    NSLog(@"Check Width");
    //Check if self.view exists
    if (WIDTH(self.view) == 0 || HEIGHT(self.view) == 0) {return;}

    NSLog(@"Remove Old Constraints");
    //Remove any previous constraints
    [self.inputView removeConstraint:self.heightConstraint];

    NSLog(@"Define Landscape");
    //Define landscape mode
    self.isLandscape = !(self.view.frame.size.width == ([[UIScreen mainScreen] bounds].size.width * ([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height)) + ([[UIScreen mainScreen] bounds].size.height *([[UIScreen mainScreen] bounds].size.width > [[UIScreen mainScreen] bounds].size.height)));

    NSLog(@"Update view height depending on orientation.");
    //Update view height depending on orientation
    if (self.isLandscape) {
        //Readjust our keyboard's height
        self.heightConstraint.constant = self.landscapeHeight;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    } else {
        NSLog(@"Detected in portrait.");
        //Re-adjust our keyboard's height
        self.heightConstraint.constant = self.portraitHeight;
        self.heightConstraint.priority = 990;
        [self.inputView addConstraint:self.heightConstraint];
        self.view.frame = CGRectMake(0, 0, WIDTH(self.view), HEIGHT(self.view));
    }
}