【发布时间】:2019-07-05 05:45:04
【问题描述】:
我有一个简单的布局,其中包含连接两个视图的约束,我将该约束存储在一个强属性中。
我的期望是,在删除其中一个视图后,约束仍然存在,但它会变为非活动状态。但事实并非如此,我的应用程序因EXC_BAD_ACCESS 异常而崩溃。
幸运的是,我能够重现该问题。我附上视图控制器的源代码。您可以将其粘贴到使用“Single View App”模板创建的新项目中。
要重现问题,请在删除其中一个视图之前和之后打印约束描述。它发生在我身上一次,约束没有被删除并且代码有效(但它只发生过一次)。使用调试器,我能够检查我删除的视图是否也没有被释放,而它已经没有层,所以它的某些部分已经被解构。在它发生之后,我注释掉了printConstraintDescriptionButtonTouchedUpInside 的实现,并在removeViewButtonTouchedUpInside 中设置了断点。当调试器在第二次按下按钮后暂停应用程序时,约束不再存在。
是否不允许对NSLayoutConstraint 实例进行强引用?我没有在文档中找到该信息。
使用 Xcode 版本 10.1 (10B61) 编译,运行 iOS Simulator iPhone SE 12.1。在运行 iOS 12.1.3 (16D5032a) 和 11.2.2 (15C202) 的物理设备上,相同的逻辑但在隔离的 sn-p 中没有失败。使用 Xcode 版本 9.4.1 进行编译不会改变任何内容。
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UIView* topView;
@property (strong, nonatomic) UIView* bottomView;
@property (strong, nonatomic) NSLayoutConstraint* constraint;
@property (strong, nonatomic) UIButton* removeViewButton;
@property (strong, nonatomic) UIButton* printConstraintDescriptionButton;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.topView = [UIView new];
self.topView.backgroundColor = [UIColor grayColor];
self.topView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.topView];
self.bottomView = [UIView new];
self.bottomView.backgroundColor = [UIColor grayColor];
self.bottomView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.bottomView];
self.removeViewButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.removeViewButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.removeViewButton setTitle:@"Remove View"
forState:UIControlStateNormal];
[self.removeViewButton addTarget:self
action:@selector(removeViewButtonTouchedUpInside)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.removeViewButton];
self.printConstraintDescriptionButton = [UIButton buttonWithType:UIButtonTypeSystem];
self.printConstraintDescriptionButton.translatesAutoresizingMaskIntoConstraints = NO;
[self.printConstraintDescriptionButton setTitle:@"Print Constraint Description"
forState:UIControlStateNormal];
[self.printConstraintDescriptionButton addTarget:self
action:@selector(printConstraintDescriptionButtonTouchedUpInside)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.printConstraintDescriptionButton];
NSDictionary* views = @{
@"topView": self.topView,
@"bottomView": self.bottomView,
@"removeViewButton": self.removeViewButton,
@"printConstraintDescriptionButton": self.printConstraintDescriptionButton
};
NSArray<NSString*>* constraints = @[
@"H:|-[topView]-|",
@"H:|-[bottomView]-|",
@"H:|-[printConstraintDescriptionButton]-|",
@"H:|-[removeViewButton]-|",
@"V:|-[topView(==44)]",
@"V:[bottomView(==44)]",
@"V:[printConstraintDescriptionButton]-[removeViewButton]-|"
];
[constraints enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:obj
options:0
metrics:nil
views:views]];
}];
self.constraint = [NSLayoutConstraint constraintWithItem:self.topView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.bottomView
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:-8.0];
self.constraint.active = YES;
}
- (void)printConstraintDescriptionButtonTouchedUpInside {
NSLog(@"%@", self.constraint);
}
- (void)removeViewButtonTouchedUpInside {
[self.bottomView removeFromSuperview];
self.bottomView = nil;
}
@end
【问题讨论】:
标签: ios objective-c memory-leaks autolayout