视图x位置的通知

时间:2014-09-03 16:55:24

标签: ios7 xcode5 nsnotificationcenter

在我正在为我的项目开发的幻灯片菜单中,我希望在内容视图滑出时添加黑色视图。要做到这一点,我需要创建一个方法,连续检查视图x位置,使黑色层变暗或变亮。此视图的位置与内容视图相同。 我以为我可以像这样使用NSNotificationCenter:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incomingNotification:) name:@"notification" object: darkViewController.view.frame.origin.x]];    

和方法:

- (void) incomingNotification:(NSNotification *)notification{
// the dark layer alpha will be 0 at origin=0 and 0.8 at bounds.size.width
float alphaToUse =  (darkViewController.view.frame.origin.x / self.view.bounds.size.width) * 0.8;
[darkViewController.view setAlpha:alphaToUse];
}

问题是我必须使用一个对象作为参数。 我是新来的通知,所以我问:用这种东西是不对的? 用另一种方式解决这个问题会更好吗?

编辑: 根据Denis的建议,我现在正在尝试使用键值观察解决方案。 我的应用程序结构如下: MenuViewController - > ContainerViewController - > DarkViewController

在MenuViewController.m中:

@interface MenuViewController ()

@property (strong,nonatomic) ContainerViewController *containerViewController;
@property (strong,nonatomic) DarkViewController *darkViewController;

@end

@implementation MenuViewController

@synthesize containerViewController,darkViewController;

# pragma mark - Views

- (void)viewDidLoad{
[super viewDidLoad];    
containerViewController = [[ContainerViewController alloc]init];
[self addChildViewController:containerViewController];
[self.view addSubview:containerViewController.view];
[containerViewController didMoveToParentViewController:self];

darkViewController = [[DarkViewController alloc]init];
[containerViewController addChildViewController:darkViewController];
[containerViewController.view addSubview:darkViewController.view];
[darkViewController didMoveToParentViewController:containerViewController];

[UIView animateWithDuration:slideDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
    [darkViewController.view setAlpha:0.7];
    containerViewController.view.frame = CGRectMake(self.view.frame.size.width - slideWidth, 0, self.view.frame.size.width, self.view.frame.size.height);
}
                 completion:^(BOOL finished) {
                     if (finished) {
                     }
                 }];

[darkViewController addObserver:self forKeyPath:@"darkViewController.view.frame.origin.x" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:    (NSDictionary *)change context:(void *)context
{
NSLog(@"x is changed");
}

当我运行这个时,我得到了这个例外:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<DarkViewController 0x10962d280> addObserver:<MenuViewController 0x10922c890> forKeyPath:@"darkViewController.view.frame.origin.x" options:1 context:0x0] was sent to an object that is not KVC-compliant for the "darkViewController" property.'

好的,似乎我找到了一个遵循此示例Notificationsin IOS

的解决方案

我刚刚在我的ContainerViewController的viewDidLoad中添加了这个

    [self addObserver:self forKeyPath:@"view.frame" options:0 context:nil];

并使用for循环实现了observer方法以查找我的DarkViewController视图

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
for (UIViewController * vc in self.childViewControllers) {
    if ([vc isKindOfClass:[DarkViewController class]]) {
        float alphaToUse =  (self.view.frame.origin.x / self.view.bounds.size.width)  * 0.8;
        [vc.view setAlpha:alphaToUse];
    }
}
}

现在我只需要了解删除removeObserver方法的位置,因为我的ContainerViewController将始终被加载...

1 个答案:

答案 0 :(得分:1)

iOS中还有另一种机制,称为键值编码和键值观察。

来自通知中心文档:

  

在设计应用程序时,不要简单地假设您应该发送通知以与感兴趣的各方进行通信。您还应该考虑键值观察,键值绑定和委派等替代方案。

     

OS X版本10.3中引入了键值绑定和键值观察,并提供了一种松散耦合数据的方法。使用键值观察,您可以请求在另一个对象的属性发生更改时收到通知。与常规通知不同,对于未观察到的更改不会有性能损失。观察对象也不需要发布通知,因为键值观察系统可以自动为您完成,尽管您仍然可以选择手动执行。

因此,如果您在制作幻灯片菜单动画时会有其他通知观察者,则可能会降低其处理性能。

最好的解决方案是在动画块中调用incomingNotification:方法(动画执行的方法)。

Apple再次提供文档:

  

虽然键值编码是有效的,但它增加的间接级别比直接方法调用稍慢。只有在您可以从其提供的灵活性中受益时,才应使用键值编码。

回答编辑问题:

This answer准确描述了您要做的事情。在某个对象的属性对象上添加观察者时,名称不应包含在属性键路径中。所以在你的情况下添加一个观察者看起来像这样:

[darkViewController addObserver:self forKeyPath:@"view.frame" options:NSKeyValueObservingOptionNew context:nil];

当试图观察一些对象属性时,不要忘记确保该对象的类符合该属性的KVC!

并且在工作完成后也不要忘记删除观察员。