【问题标题】:KVO check for change of clipsToBounds of all subviews in an UIView in objective cKVO检查目标c中UIView中所有子视图的clipsToBounds的变化
【发布时间】:2022-01-25 07:30:23
【问题描述】:

我正在尝试为 UIView 中所有子视图的 clipsToBounds 属性实现 KVO 示例。我不太明白如何更改 observeValueForKeyPath 方法中的值。我正在使用此代码:

-(void)ViewDidLoad{
        [self.navigationController.view addObserver:self forKeyPath:@"clipsToBounds" options:NSKeyValueObservingOptionNew |
         NSKeyValueObservingOptionOld context:nil];
    }
    
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"Triggered...")
    }

当我更改我拥有的 UIView 中存在的子视图的属性 clipToBounds 时会触发它。对于发生的每个触发器,我都需要将值更改回 false。我应该在 observeValueForKeyPath 中写什么来更改 clipsToBounds 属性?任何帮助表示赞赏。

【问题讨论】:

  • “ViewDidLoad”还是“viewDidLoad”?
  • viewDidLoad 是

标签: ios objective-c


【解决方案1】:

当然,添加观察者必须在它起作用之前完成。 永远不会调用您在“ViewDidLoad”中的拼写错误,因为它应该是“viewDidLoad”。 除此之外,您的 KVO 模式可能看起来像..

static void *kvoHelperClipsToBounds = &kvoHelperClipsToBounds;

-(void)viewDidLoad {
    [self.navigationController.view addObserver:self forKeyPath:@"clipsToBounds" options:NSKeyValueObservingOptionNew context:&kvoHelperClipsToBounds];
}
    
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == kvoHelperClipsToBounds) {
        NSLog(@"context compared successful...");
        //be careful what you cast to.. i dont check isKindOf here.
        UINavigationBar* navbar = (UINavigationBar*)object;
        if (navbar.subviews.count > 1) {
            __kindof UIView *sub = navbar.subviews[1];
            if (sub.clipsToBounds) {
                dispatch_async(dispatch_get_main_queue(),^{
                    sub.clipsToBounds = NO;
                    [self.navigationItem.titleView layoutIfNeeded];
                });
            }
        }
    } 

    // or compare against the keyPath
    else if ([keyPath isEqualToString:@"clipsToBounds"]) {
        NSLog(@"classic Key compare Triggered...");
    }
    else
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

[super observeValueForKeyPath...] 将无法识别的 keyPath 传递给 super 以让 super 的类 KVO 工作,否则如果 super 的实现依赖于观察它们,这些将被忽略。如果需要,这还应该解释如何观察所有子视图。但是考虑一下,如果 UIView 的子类实现它并且所有子视图(或您喜欢的子视图)也将从这个特殊的子类继承,那么可能有数百个子视图触发 observeValueForKeyPath。

当您在观察它的 KVO 中更改 clipsToBounds 时,您可能会调用一个循环,特别是当您同时观察旧值和新值时。你会改变属性,属性触发 kvo,kvo 改变属性,属性触发 kvo 和 on 等等。

设置[self.navigationController.view setClipsToBounds:YES] 以更改属性。但是如果在 KVO 内部完成,它会再次触发 KVO,如前所述。 通常您会在-initWithFrame: 或-initWithCoder: 或通过Interface Builder 中设置clipsToBounds,也许只是观察它是否被更改以适应其他代码。

旁注:上下文只需要唯一以将其与其他 KVO 区分开来。它也可以是对真实对象指针的引用。

不要忘记添加的观察者必须在释放之前被移除。

【讨论】:

  • 谢谢,但是如何更改子视图的属性值?这段代码究竟是做什么的? [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  • 感谢更新的解释。我真正需要的是当clipsToBounds 属性在KVO 之外更改为true 时,然后当它进入KVO 时将属性从true 更改为false。其实我想实现这个答案stackoverflow.com/questions/47121427/… 但似乎它不起作用。
  • ;-) 一些秘密。改进你自己的问题(例如这个带有一些“编辑”的问题)我认为比用完整的 objc 语句评论一个快速线程更好。当然它可能会闪烁,因为 KVO 没有在属性更改之前触发。旁注:我了解到,通常最好坚持使用给定的操作系统 UI,而不是对其进行大量调整,因为稍后这可能会中断,您必须再次找到使其工作的方法。这特别适用于 NavigationViewController 的东西。
  • 和this 确实是迄今为止最好的解决方案.. 因为它确实有效。
  • ofObject:(UINavigationBar)object ?应该是 ofObject:(id)object kvo 适用于驻留在接口属性上的所有 nsobjects 而不仅仅是 UINavbar .. 你应该在观察者方法中将 id 转换为 UINavigationBar* navbar = (UINavigationBar*)object;。
猜你喜欢
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多