为什么iOS自动布局会导致Retina显示前显示的舍入错误(包括unit testing)

我目前很难理解为什么iPad 2上的下列unit testing失败。自动布局似乎在超view内的错位置view相对于两个布局约束所要求的精确对中而言略微(0.5点)。 尤其令人感到奇怪的是,关键testing(但是最后的断言)在iPhone 5上传递,所以明显的四舍五入错误只影响一个(iOS 6)平台。 这里发生了什么?

更新1我已经改变了代码,以确保这两个框架是足够的宽度和高度的限制,即使translatesAutoresizingMaskIntoConstraintsNO ,作为一个可能相关的补救措施build议在这里 。 但是,这显然不会改变这种情况。

 #import "BugTests.h" @implementation BugTests - (void)testCenteredLayout { UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 88)]; superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; superview.translatesAutoresizingMaskIntoConstraints = YES; UILabel *view = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; view.text = @"Single Round against iPad."; view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; view.translatesAutoresizingMaskIntoConstraints = NO; [view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:206.0]]; [view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: 21.0]]; [superview addSubview:view]; [superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; [superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; STAssertEquals(superview.center, CGPointMake(384, 44), nil); // succeeds STAssertEquals(view.center, CGPointMake( 0, 0), nil); // succeeds [superview setNeedsLayout]; [superview layoutIfNeeded]; STAssertTrue(!superview.hasAmbiguousLayout, nil); STAssertEquals(superview.frame.size, CGSizeMake(768, 88), nil); // succeeds STAssertEquals(view.frame.size, CGSizeMake(206, 21), nil); // succeeds STAssertEquals(superview.center, CGPointMake(384, 44), nil); // succeeds STAssertEquals(superview.center, view.center, nil); // fails: why? STAssertEquals(view.center, CGPointMake(384, 44.5), nil); // succeeds: why? } @end 

更新2我在第二次unit testing中隔离了(显然)同样的问题的另一个实例。 这次它涉及一个顶部(而不是中心)约束,这次分数点坐标似乎是触发器。 (testing也成功的前视网膜设备,例如与y = 951 ,即奇点坐标。)我已经检查了各种模拟器configuration(我的物理iPad 2和iPhone 5旁边)确实似乎绑在没有Ratina展示。 (再次感谢@ArkadiuszHolko的领导。)

我目前从这些testing中的感觉是,如果需要在视网膜前显示器上进行点精确的自动布局,则必须避免奇数高度和分数的y坐标。 但为什么?

 - (void)testNonRetinaAutoLayoutProblem2 { UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 1004)]; superview.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; superview.translatesAutoresizingMaskIntoConstraints = YES; CGFloat y = 950.5; // see eg pageControlTopConstraint UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)]; view.translatesAutoresizingMaskIntoConstraints = NO; [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]]; [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]]; [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:y]]; [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:8]]; [superview addSubview:view]; [superview setNeedsLayout]; [superview layoutIfNeeded]; STAssertTrue(!superview.hasAmbiguousLayout, nil); STAssertTrue(!view.hasAmbiguousLayout, nil); STAssertEquals(superview.frame, CGRectMake(0, 0, 768, 1004), nil); // succeeds STAssertEquals(view.frame, CGRectMake(0, y, 768, 8), nil); // fails: why? STAssertEquals(view.frame, CGRectMake(0, y + 0.5, 768, 8), nil); // succeeds: why? } 

你已经显示的是,自动布局憎恶错位的意见。 在非视网膜设备上最接近的像素是最近的 ,所以它整数。 在视网膜屏幕上,最接近的像素是最接近的半点 ,所以它会四舍五入到最接近的0.5。 你可以通过在第二次testing中将y改为950.25来certificate这一点,并注意到view.frame保持为{{0,950.5},{768,8}}(而不是变为{{0,950.25},{768,8} })。

(只是为了certificate它是四舍五入的,如果将y更改为950.2,则view.frame变为{{0,950},{768,8}}。)