提问人:ashipma 提问时间:10/15/2021 最后编辑:ashipma 更新时间:10/16/2021 访问量:923
未设置 UIView 隐藏
UIView hidden is not getting set
问:
我有一个 UIView 子类,它被添加为 UIStackView 的排列子视图。根据模型中的数据,我想隐藏或显示排列好的子视图(称为),但问题是当我去隐藏它时,即使我设置了,它仍然显示。myView
myView.hidden = NO
myView.hidden = YES
例如,以下是我拥有的代码。它从隐藏视图开始,根据是否设置,它将显示 myView。或者这就是应该发生的事情。myModel.someProperty
我已经设置了一个断点并单步执行此代码,并在执行第 4 行之前使用 LLDB 进行验证。然后,我在跨过第 4 行后立即检查了该值,它仍然是 YES。但是第 4 行显式将其设置为 NO,并且 myView 实现中的任何内容都不会覆盖甚至设置或检查自身的隐藏属性。因此,在此上设置隐藏只会转到标准的 UIView 方法。那么它怎么可能仍然是肯定的呢?self.myView.hidden == YES
setHidden:
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 行添加了一个循环,这将导致视图再次隐藏。这次有效。因此,如果我设置两次,那么它实际上将设置为 NO。但是,如果我只设置一次,那么它就会保持在 YES。我不明白这是怎么回事。myView.hidden = NO
有谁知道这里可能出了什么问题或如何进一步解决这个问题?我使用LLDB的命令来查看每组属性之前和之后的值。因此,在第 4 行之前,它被设置为 YES,这是正确的。然后,在第 4 行之后,我检查了它,它仍然设置为 YES,即使它在上一行中显式设置为 NO。然后,我检查了一下,它进入了第 8 行的循环(即使它不应该像它应该的那样隐藏)。然后我在第 10 行之前再次检查,仍然是 YES,我在第 10 行之后检查,最终正确设置为 NO。po
myView.isHidden
myView.hidden
但我只是不确定发生了什么。这是非常违反直觉的,因为我明确将其设置为 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。
设置前 hidden=NO: <MyView: 0x117ef6eb0;帧 = (0 49.6667; 123.667 20.3333);隐藏 = 是;layer = <CALayer:0x280ddaa20>>
设置后 hidden=NO: <MyView: 0x117ef6eb0;帧 = (0 49.6667; 123.667 20.3333);隐藏 = 是;layer = <CALayer:0x280ddaa20>>
下一组日志语句在循环内,由于我将 myView.hidden 设置为 NO,因此它甚至不应该输入,但它仍然会进入,因为值仍然是 YES。在这里,它看起来可以正常工作。第一个日志语句显示它是可见的,然后下一个日志语句显示它是隐藏的。
SHOULD NOT BE HERE - 再次设置 hidden=NO 之前: <MyView: 0x117ef6eb0;帧 = (0 49.6667; 123.667 20.3333);隐藏 = 是;layer = <CALayer:0x280ddaa20>>
SHOULD NOT BE HERE - 再次设置 hidden=NO 后: <MyView: 0x117ef6eb0;帧 = (0 49.6667; 123.667 20.3333);layer = <CALayer:0x280ddaa20>>
最后,不再隐藏:<MyView:0x117ef6eb0;帧 = (0 49.6667; 123.667 20.3333);layer = <CALayer:0x280ddaa20>>
更新 2
我知道这段代码似乎可以自行运行,但它在我的项目中对我不起作用。我将在此处显示我的视图类的代码,以及显示代码中观察到的相同行为的调试会话的输出。
我知道它可能在我的代码中,但与此同时,我只是不明白如何。我的所有代码都包含对 .没什么额外的。在调用 setHidden 之前,hidden 的值为 YES。调用后,该值仍为 YES。我不明白。我想知道这是否可能是编译器问题。我知道这些编译器经过了很好的测试,但同时我也不明白我的代码是怎么回事。我只是设置隐藏 = NO,但除非我这样做两次,否则它不起作用。setHidden:
setHidden:NO
调试会话
这是LLDB的输出。我在视图即将取消隐藏之前设置了一个断点(前面代码片段中的第 3 行)。此时,.myView.hidden = YES
因此,我所做的只是为该视图打印隐藏的值,它正确地显示是。在此之后,我跑去尝试更新它,但这不起作用,正如在调用语句正下方打印出来的调试语句中所示。它仍然显示.为了确定,我还继续再次打印了该值,它仍然显示隐藏 = YES。call self.myView.hidden = NO
hidden = YES;
(lldb) p self.myView.hidden
(BOOL) $12 = 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) $13 = NO
(lldb) p self.myView.hidden
(BOOL) $15 = 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) $16 = NO
(lldb) p self.myView.hidden
(BOOL) $17 = NO
这是我的视图类的代码,它被显示和隐藏。我没有重写或对隐藏属性执行任何操作,因此任何调用都会直接转到 UIView 上的方法。setHidden:
我的视图.h
#import <UIKit/UIKit.h>
#import "MyModel.h"
@interface MyView : UIView
@property (strong, nonatomic, nullable) MyModel *myModel;
@end
我的View.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
如果还有什么我应该发布的会有所帮助,或者有什么我可以尝试的,请告诉我。我可以在我的代码中只写两次值,但是在不理解为什么我必须这样做的情况下,我觉得这有点危险,因为我怎么知道两次总是足够的?另外,必须连续两次将变量设置为相同的值才能使其工作,这很奇怪。
感谢大家对此的帮助。
答:
这似乎是由于 UIStackView 中的一个错误,如果您多次隐藏视图,它会累积该视图的隐藏计数。因此,例如,假设视图层次结构如下:
- UIStack视图
- 我的视图
然后,如果将 hidden=YES 设置为三次,则需要设置 hidden=NO 三次才能将其实际设置为 NO。反过来说,这似乎不是一个问题。因此,如果您将其 hidden=NO 设置为三次,您可以将其设置为 hidden=YES 一次,它就会被隐藏。MyView
此 StackOverflow 答案中提供了更多信息:https://stackoverflow.com/a/45599835/5140550
我不确定是否已将此错误报告给Apple,但它似乎是UIStackView中的一个错误。现在我只需要找出一种干净的方法来在我的代码中处理这个问题。
评论
是的,在对 .UIStackView
您应该能够通过将以下内容添加到自定义视图类来纠正此问题:
- (void)setHidden:(BOOL)hidden {
if (self.isHidden != hidden) {
[super setHidden:hidden];
}
}
下面是一个完整的示例,显示了问题,并显示了“修复”:https://github.com/DonMag/StackViewBug
评论
po
p
p self.myView.hidden
self.myView.hidden
self.myView.isHidden
isHidden
[self.myView isHidden]
self.myView.hidden
myView.hidden
[myView isHidden]
p self.myView.hidden
NO
YES