在我正在为我的项目开发的幻灯片菜单中,我希望在内容视图滑出时添加黑色视图。要做到这一点,我需要创建一个方法,连续检查视图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将始终被加载...
答案 0 :(得分:1)
iOS中还有另一种机制,称为键值编码和键值观察。
来自通知中心文档:
在设计应用程序时,不要简单地假设您应该发送通知以与感兴趣的各方进行通信。您还应该考虑键值观察,键值绑定和委派等替代方案。
OS X版本10.3中引入了键值绑定和键值观察,并提供了一种松散耦合数据的方法。使用键值观察,您可以请求在另一个对象的属性发生更改时收到通知。与常规通知不同,对于未观察到的更改不会有性能损失。观察对象也不需要发布通知,因为键值观察系统可以自动为您完成,尽管您仍然可以选择手动执行。
因此,如果您在制作幻灯片菜单动画时会有其他通知观察者,则可能会降低其处理性能。
最好的解决方案是在动画块中调用incomingNotification:方法(动画执行的方法)。
Apple再次提供文档:
虽然键值编码是有效的,但它增加的间接级别比直接方法调用稍慢。只有在您可以从其提供的灵活性中受益时,才应使用键值编码。
回答编辑问题:
This answer准确描述了您要做的事情。在某个对象的属性对象上添加观察者时,名称不应包含在属性键路径中。所以在你的情况下添加一个观察者看起来像这样:
[darkViewController addObserver:self forKeyPath:@"view.frame" options:NSKeyValueObservingOptionNew context:nil];
当试图观察一些对象属性时,不要忘记确保该对象的类符合该属性的KVC!
并且在工作完成后也不要忘记删除观察员。