未设置隐藏的 UIView
UIView hidden is not getting set
我有一个 UIView subclass 添加为 UIStackView 的 ar运行ged 子视图。根据模型中的数据,我想隐藏或显示 ar运行ged 子视图(称为 myView
),但问题是当我去隐藏它时,即使我设置 myView.hidden = NO
,还是显示myView.hidden = YES
.
例如,下面是我的代码。它从隐藏视图开始,根据是否设置了 myModel.someProperty
,它将显示 myView。或者这就是应该发生的事情。
我已经设置了一个断点并单步执行了这段代码,并在第 4 行执行之前使用 LLDB 验证 self.myView.hidden == YES
。然后我在跨过第 4 行后立即检查了该值,它仍然是 YES。但是第 4 行明确地将其设置为 NO,并且在 myView 的实现中没有任何内容覆盖甚至设置或检查其自身的隐藏 属性。所以设置隐藏只是进入标准的 UIView setHidden:
方法。那怎么可能还是YES呢?
1. //currently, self.myView.hidden is YES
2.
3. if (self->_myModel.someProperty) {
4. self.myView.hidden = NO;
5.
6. //for some reason, self.myView.hidden is still YES
7.
8. while (self.myView.isHidden) {
9. NSLog(@"myView is hidden, but it should not be");
10. self.myView.hidden = NO;
11. }
12. NSLog(@"myView is no longer hidden");
13. }
我在第 8 行添加了一个循环,它将导致视图再次被隐藏。这次成功了。所以如果我设置 myView.hidden = NO
两次,那么它实际上会被设置为 NO。但如果我只设置一次,那么它会保持在 YES。我不明白这是怎么回事。
有谁知道这里可能出了什么问题或如何进一步解决这个问题?我用LLDB的po
命令查看了每组属性前后myView.isHidden
的值。所以在第 4 行之前,它被设置为 YES,这是正确的。然后,在第 4 行之后,我检查了它,它仍然设置为 YES,即使它在上一行中明确设置为 NO。然后,我检查了一下,它进入了第 8 行的循环(即使它不应该像它应该的那样被隐藏)。然后我在第 10 行之前再次检查,myView.hidden
仍然是 YES,我在第 10 行之后检查,它最终正确设置为 NO。
但我只是不确定发生了什么。这是非常违反直觉的,因为我明确地将其设置为 NO,但直到我将其设置两次为 NO 后它才被设置。
是否有解决此问题或找出问题所在的好方法,或者有人对可能出现的问题有任何建议吗?
更新
我更新了代码以添加一些额外的日志语句。在 LLDB 中检查 属性 时,我也使用了 p self.myView.hidden
。
1. // at this point, self.myView.hidden = YES
2.
3. if (self->_myModel.someProperty) {
4. NSLog(@"Before setting hidden=NO: %@", self->_myView);
5. self.myView.hidden = NO;
6. NSLog(@"After setting hidden=NO: %@", self->_myView);
7.
8. while ([self.myView isHidden]) {
9. NSLog(@"SHOULD NOT BE HERE - Before setting hidden=NO again: %@", self->_myView);
10. self.myView.hidden = NO;
11. NSLog(@"SHOULD NOT BE HERE - After setting hidden=NO again: %@", self->_myView);
12. }
13.
14. NSLog(@"Finally, no longer hidden: %@", self->_myView);
15. }
这是这段代码的日志语句。第一个日志语句是正确的,因为它显示 myView.hidden == YES。然而,第二个日志语句对我来说似乎是错误的,因为它仍然显示 myView.hidden == YES 即使在前一行它只是设置为 NO.
Before setting hidden=NO: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
After setting hidden=NO: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
下一组日志语句在循环内,它甚至不应该进入循环,因为我将 myView.hidden 设置为 NO,但无论如何它都会进入,因为值仍然是 YES。在这里它看起来工作正常。第一个日志语句显示它是可见的,然后下一个日志语句显示它是隐藏的。
SHOULD NOT BE HERE - Before setting hidden=NO again: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
SHOULD NOT BE HERE - After setting hidden=NO again: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x280ddaa20>>
Finally, no longer hidden: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x280ddaa20>>
更新 2
我知道这段代码似乎可以独立运行,但在我的项目中对我不起作用。我将在此处显示我的视图 class 的代码以及调试会话的输出,显示在代码中观察到的相同行为。
而且我知道它可能在我的代码中,但与此同时,我只是不知道如何实现。我的所有代码都包含这里是对 setHidden:
的调用。没什么额外的。在调用setHidden之前,hidden的值为YES。调用setHidden:NO
后,值还是YES。我不明白这个。我想知道这是否可能是编译器问题。我知道这些编译器都经过了很好的测试,但同时我也不明白我的代码是怎么来的。我只是简单地设置了 hidden = NO,但它不起作用,除非我设置两次。
调试会话
这是 LLDB 的输出。我在视图即将取消隐藏之前设置了一个断点(前面代码片段中的第 3 行)。此时,myView.hidden = YES
.
所以我所做的就是打印那个视图的 hidden 值,它正确地显示了 YES。在此之后,我 运行 call self.myView.hidden = NO
尝试更新它,但这不起作用,正如在调用语句下方打印的调试语句中所见。它仍然显示 hidden = YES;
。我也继续并再次打印该值只是为了确定,它仍然显示 hidden = YES.
(lldb) p self.myView.hidden
(BOOL) = YES
(lldb) call self.myView.hidden = NO
<MyView: 0x12b138980; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x283addfe0>> MyView::setHidden:NO
(BOOL) = NO
(lldb) p self.myView.hidden
(BOOL) = YES
接下来,我只是再次将该值设置为 NO,这一次它的工作原理可以从调试语句中看出,我还再次打印了该值以备不时之需。
(lldb) call self.myView.hidden = NO
<MyView: 0x12b138980; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x283addfe0>> MyView::setHidden:NO
(BOOL) = NO
(lldb) p self.myView.hidden
(BOOL) = NO
这是显示和隐藏我的视图 class 的代码。我没有覆盖或对隐藏的 属性 做任何事情,所以对 setHidden:
的任何调用都会直接转到 UIView 上的方法。
MyView.h
#import <UIKit/UIKit.h>
#import "MyModel.h"
@interface MyView : UIView
@property (strong, nonatomic, nullable) MyModel *myModel;
@end
MyView.m
#import "MyView.h"
@interface MyView ()
@property (strong, nonatomic) UILabel *label;
//other UI components are here, but they are just more labels and an image view
@end
@implementation MyView
- (instancetype)init {
return [self initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (void)initialize {
[self addSubview:self.label];
//add other labels and the image view
[NSLayoutConstraint activateConstraints:@[
[self.label.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.leadingAnchor],
[self.label.topAnchor constraintGreaterThanOrEqualToAnchor:self.topAnchor],
[self.label.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
//more constraints for the other labels and the image
]];
}
- (void)setMyModel:(MyModel *)myModel {
self->_myModel = myModel;
[self updateDisplay];
}
- (void)updateDisplay {
//set the text of all the labels based on the model
}
- (UILabel *)label {
if (!self->_label) {
self->_label = [[UILabel alloc] init];
self->_label.translatesAutoresizingMaskIntoConstraints = NO;
self->_label.numberOfLines = 0;
self->_label.text = @"My Text:";
[self->_label setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self->_label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
return self->_label;
}
@end
请让我知道是否有任何其他我应该 post 会有所帮助的事情,或者是否有任何我可以尝试的事情。我可以在我的代码中只写两次值,但不理解为什么我必须这样做,我觉得这有点危险,因为我怎么知道两次就足够了?另外,必须连续两次将变量设置为相同的值才能工作,这很奇怪。
感谢大家对此的帮助。
这看起来是由于 UIStackView 中的一个错误,如果您多次隐藏一个视图,它会累积该视图的隐藏次数。因此,例如,想象一个像这样的视图层次结构:
- UIStackView
- 我的视图
那么,如果你设置了3次MyView
hidden=YES,那么要设置3次hidden=NO才能真正设置为NO。这似乎不是另一个问题。所以设置3次hidden=NO,只设置一次hidden=YES就隐藏了。
这个 Whosebug 答案中有更多信息:
我不确定是否已将此错误报告给 Apple,但它似乎是 UIStackView 中的错误。现在我只需要找出一种干净的方法来在我的代码中处理这个问题。
是的,在 UIStackView
.
中动画显示/隐藏排列的子视图时存在错误/怪癖
您应该可以通过将此添加到您的自定义视图来更正此问题 class:
- (void)setHidden:(BOOL)hidden {
if (self.isHidden != hidden) {
[super setHidden:hidden];
}
}
这是一个完整的示例,显示了问题并显示了“修复”:https://github.com/DonMag/StackViewBug
我有一个 UIView subclass 添加为 UIStackView 的 ar运行ged 子视图。根据模型中的数据,我想隐藏或显示 ar运行ged 子视图(称为 myView
),但问题是当我去隐藏它时,即使我设置 myView.hidden = NO
,还是显示myView.hidden = YES
.
例如,下面是我的代码。它从隐藏视图开始,根据是否设置了 myModel.someProperty
,它将显示 myView。或者这就是应该发生的事情。
我已经设置了一个断点并单步执行了这段代码,并在第 4 行执行之前使用 LLDB 验证 self.myView.hidden == YES
。然后我在跨过第 4 行后立即检查了该值,它仍然是 YES。但是第 4 行明确地将其设置为 NO,并且在 myView 的实现中没有任何内容覆盖甚至设置或检查其自身的隐藏 属性。所以设置隐藏只是进入标准的 UIView setHidden:
方法。那怎么可能还是YES呢?
1. //currently, self.myView.hidden is YES
2.
3. if (self->_myModel.someProperty) {
4. self.myView.hidden = NO;
5.
6. //for some reason, self.myView.hidden is still YES
7.
8. while (self.myView.isHidden) {
9. NSLog(@"myView is hidden, but it should not be");
10. self.myView.hidden = NO;
11. }
12. NSLog(@"myView is no longer hidden");
13. }
我在第 8 行添加了一个循环,它将导致视图再次被隐藏。这次成功了。所以如果我设置 myView.hidden = NO
两次,那么它实际上会被设置为 NO。但如果我只设置一次,那么它会保持在 YES。我不明白这是怎么回事。
有谁知道这里可能出了什么问题或如何进一步解决这个问题?我用LLDB的po
命令查看了每组属性前后myView.isHidden
的值。所以在第 4 行之前,它被设置为 YES,这是正确的。然后,在第 4 行之后,我检查了它,它仍然设置为 YES,即使它在上一行中明确设置为 NO。然后,我检查了一下,它进入了第 8 行的循环(即使它不应该像它应该的那样被隐藏)。然后我在第 10 行之前再次检查,myView.hidden
仍然是 YES,我在第 10 行之后检查,它最终正确设置为 NO。
但我只是不确定发生了什么。这是非常违反直觉的,因为我明确地将其设置为 NO,但直到我将其设置两次为 NO 后它才被设置。
是否有解决此问题或找出问题所在的好方法,或者有人对可能出现的问题有任何建议吗?
更新
我更新了代码以添加一些额外的日志语句。在 LLDB 中检查 属性 时,我也使用了 p self.myView.hidden
。
1. // at this point, self.myView.hidden = YES
2.
3. if (self->_myModel.someProperty) {
4. NSLog(@"Before setting hidden=NO: %@", self->_myView);
5. self.myView.hidden = NO;
6. NSLog(@"After setting hidden=NO: %@", self->_myView);
7.
8. while ([self.myView isHidden]) {
9. NSLog(@"SHOULD NOT BE HERE - Before setting hidden=NO again: %@", self->_myView);
10. self.myView.hidden = NO;
11. NSLog(@"SHOULD NOT BE HERE - After setting hidden=NO again: %@", self->_myView);
12. }
13.
14. NSLog(@"Finally, no longer hidden: %@", self->_myView);
15. }
这是这段代码的日志语句。第一个日志语句是正确的,因为它显示 myView.hidden == YES。然而,第二个日志语句对我来说似乎是错误的,因为它仍然显示 myView.hidden == YES 即使在前一行它只是设置为 NO.
Before setting hidden=NO: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
After setting hidden=NO: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
下一组日志语句在循环内,它甚至不应该进入循环,因为我将 myView.hidden 设置为 NO,但无论如何它都会进入,因为值仍然是 YES。在这里它看起来工作正常。第一个日志语句显示它是可见的,然后下一个日志语句显示它是隐藏的。
SHOULD NOT BE HERE - Before setting hidden=NO again: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x280ddaa20>>
SHOULD NOT BE HERE - After setting hidden=NO again: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x280ddaa20>>
Finally, no longer hidden: <MyView: 0x117ef6eb0; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x280ddaa20>>
更新 2
我知道这段代码似乎可以独立运行,但在我的项目中对我不起作用。我将在此处显示我的视图 class 的代码以及调试会话的输出,显示在代码中观察到的相同行为。
而且我知道它可能在我的代码中,但与此同时,我只是不知道如何实现。我的所有代码都包含这里是对 setHidden:
的调用。没什么额外的。在调用setHidden之前,hidden的值为YES。调用setHidden:NO
后,值还是YES。我不明白这个。我想知道这是否可能是编译器问题。我知道这些编译器都经过了很好的测试,但同时我也不明白我的代码是怎么来的。我只是简单地设置了 hidden = NO,但它不起作用,除非我设置两次。
调试会话
这是 LLDB 的输出。我在视图即将取消隐藏之前设置了一个断点(前面代码片段中的第 3 行)。此时,myView.hidden = YES
.
所以我所做的就是打印那个视图的 hidden 值,它正确地显示了 YES。在此之后,我 运行 call self.myView.hidden = NO
尝试更新它,但这不起作用,正如在调用语句下方打印的调试语句中所见。它仍然显示 hidden = YES;
。我也继续并再次打印该值只是为了确定,它仍然显示 hidden = YES.
(lldb) p self.myView.hidden
(BOOL) = YES
(lldb) call self.myView.hidden = NO
<MyView: 0x12b138980; frame = (0 49.6667; 123.667 20.3333); hidden = YES; layer = <CALayer: 0x283addfe0>> MyView::setHidden:NO
(BOOL) = NO
(lldb) p self.myView.hidden
(BOOL) = YES
接下来,我只是再次将该值设置为 NO,这一次它的工作原理可以从调试语句中看出,我还再次打印了该值以备不时之需。
(lldb) call self.myView.hidden = NO
<MyView: 0x12b138980; frame = (0 49.6667; 123.667 20.3333); layer = <CALayer: 0x283addfe0>> MyView::setHidden:NO
(BOOL) = NO
(lldb) p self.myView.hidden
(BOOL) = NO
这是显示和隐藏我的视图 class 的代码。我没有覆盖或对隐藏的 属性 做任何事情,所以对 setHidden:
的任何调用都会直接转到 UIView 上的方法。
MyView.h
#import <UIKit/UIKit.h>
#import "MyModel.h"
@interface MyView : UIView
@property (strong, nonatomic, nullable) MyModel *myModel;
@end
MyView.m
#import "MyView.h"
@interface MyView ()
@property (strong, nonatomic) UILabel *label;
//other UI components are here, but they are just more labels and an image view
@end
@implementation MyView
- (instancetype)init {
return [self initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (void)initialize {
[self addSubview:self.label];
//add other labels and the image view
[NSLayoutConstraint activateConstraints:@[
[self.label.leadingAnchor constraintGreaterThanOrEqualToAnchor:self.leadingAnchor],
[self.label.topAnchor constraintGreaterThanOrEqualToAnchor:self.topAnchor],
[self.label.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
//more constraints for the other labels and the image
]];
}
- (void)setMyModel:(MyModel *)myModel {
self->_myModel = myModel;
[self updateDisplay];
}
- (void)updateDisplay {
//set the text of all the labels based on the model
}
- (UILabel *)label {
if (!self->_label) {
self->_label = [[UILabel alloc] init];
self->_label.translatesAutoresizingMaskIntoConstraints = NO;
self->_label.numberOfLines = 0;
self->_label.text = @"My Text:";
[self->_label setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
[self->_label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
}
return self->_label;
}
@end
请让我知道是否有任何其他我应该 post 会有所帮助的事情,或者是否有任何我可以尝试的事情。我可以在我的代码中只写两次值,但不理解为什么我必须这样做,我觉得这有点危险,因为我怎么知道两次就足够了?另外,必须连续两次将变量设置为相同的值才能工作,这很奇怪。
感谢大家对此的帮助。
这看起来是由于 UIStackView 中的一个错误,如果您多次隐藏一个视图,它会累积该视图的隐藏次数。因此,例如,想象一个像这样的视图层次结构:
- UIStackView
- 我的视图
那么,如果你设置了3次MyView
hidden=YES,那么要设置3次hidden=NO才能真正设置为NO。这似乎不是另一个问题。所以设置3次hidden=NO,只设置一次hidden=YES就隐藏了。
这个 Whosebug 答案中有更多信息:
我不确定是否已将此错误报告给 Apple,但它似乎是 UIStackView 中的错误。现在我只需要找出一种干净的方法来在我的代码中处理这个问题。
是的,在 UIStackView
.
您应该可以通过将此添加到您的自定义视图来更正此问题 class:
- (void)setHidden:(BOOL)hidden {
if (self.isHidden != hidden) {
[super setHidden:hidden];
}
}
这是一个完整的示例,显示了问题并显示了“修复”:https://github.com/DonMag/StackViewBug