【发布时间】:2012-03-23 14:15:24
【问题描述】:
我正在尝试掌握使用通知的窍门。在我的视图控制器类中,我有一个 bool isFullScreen。当这个 bool 的值发生变化时,我想向所有观察类发送通知。我不太确定如何去做,因为 BOOL 不是对象。我将如何做到这一点?
【问题讨论】:
标签: iphone objective-c ios
我正在尝试掌握使用通知的窍门。在我的视图控制器类中,我有一个 bool isFullScreen。当这个 bool 的值发生变化时,我想向所有观察类发送通知。我不太确定如何去做,因为 BOOL 不是对象。我将如何做到这一点?
【问题讨论】:
标签: iphone objective-c ios
[[NSNotificationCenter defaultCenter] postNotificationName:YourNotificationName object:[NSNumber numberWithBool:isFullScreen]]; //YourNotificationName is a string constant
KVO 示例:
如果你用 KVO 来做,它会像下面这样......:
[self addObserver:self forKeyPath:@"isFullScreen" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString: @"isFullScreen"]) {
BOOL newValue = [[change objectForKey:NSKeyValueChangeNewKey] boolValue];
}
}
//and in dealloc
[self removeObserver:self forKeyPath:@"isFullScreen" ];
【讨论】:
只需wrap NSNumber 中的 BOOL:
[NSNumber numberWithBool:myBool]
【讨论】:
您可以在 NSNumber 中包装一个 BOOL,例如提到的 bandejapaisa 和铍。但是,为了通知观察者对简单属性的更改,最好使用键值观察 (KVO),而不是 NSNotificationCenter。只要您实现或符合@synthesized KVC 的访问器方法,您就可以“免费”获得 KVO。像这样的:
// In your .h:
@interface YourViewController : UIViewController
@property (getter = isFullScreen) BOOL fullScreen;
@end
// In your .m:
@implementation YourViewController
@synthesize fullScreen;
@end
// In your observer class(es):
// Start observing the viewController for changes to fullScreen (in awakeFromNib, or wherever it makes sense)
[self.viewController addObserver:self forKeyPath:@"fullScreen" options:0 context:NULL];
// This method is called when an observed value changes
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == viewController && [keyPath isEqualToString:@"fullScreen"])
{
if (self.viewController.isFullScreen)
{
// Do whatever you need to do in response to isFullScreen being true
}
else
{
// Do whatever you need to do in response to isFullScreen being false
}
}
}
为此,您需要确保实际调用了 fullScreen 属性的设置器。因此,请始终使用 self.fullScreen = YES 或 [self setFullScreen:YES] 而不是 fullScreen = YES。否则不调用setter方法,也不触发KVO。
您应该阅读documentation on KVO。理解它对于成为一名优秀的 iOS 程序员非常重要。
【讨论】:
您可以通过使用 NSMutableString* 作为@"YES" 和@"NO" 来解决这个问题。然后,当您将字符串设置为 @"YES" 并且在 KVO 中观察到的所有内容都会收到通知:
[myStringProperty setString:@"YES"];
您必须使用 NSString setString 值。这就是它的实际调用方式。
警告不要使用:
myStringProperty = @"YES";
(这不会产生 KVO 通知。)
【讨论】:
通知的object 应该是发布通知的对象,而不是NSNumber。这一点很重要,这样观察者可以观察特定的实例,并且调用者可以清楚地知道所有的值是什么。在object 中传递数据是获得“不响应选择器”崩溃的简单方法。更改数据通常放在 userInfo 字典中,但简单的 BOOL 通常使用两个通知来处理。在这种情况下,您将拥有:
MYViewControlDidEnterFullScreenNotification
MYViewControlDidExitFullScreenNotification
object 应该是相关的视图控制器。
请注意,这些通知的时间安排非常明确。两者都发生在状态改变之后。您还可以拥有等效的Will 通知。查看notification list 的NSWindow 以获得如何正确执行此操作的一个很好的示例。特别注意NSWindowDidEnterFullScreenNotification 及其亲属。
您可能还对Some thoughts on NSNotifications感兴趣。
KVO 上的 cmets 很好,而且 KVO 通常是实现这一目标的不错方式。但是通知也很好,并且比 KVO 更容易理解和调试。
【讨论】:
通知的对象字段旨在传递发送者而不是附加参数
正确的做法是使用userInfo发送键值字典
例如
- (void)postNotificationFullScreen //post notification method and logic
{
NSString *notificationName = @"applicationFullScreen";
NSString *key = @"fullScreen";
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:self.fullScreen] forKey:key];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil userInfo:dictionary];
}
阅读本文
NSString *notificationName = @"applicationFullScreen";
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(useFullScreen:)
name:notificationName
object:nil];
- (void)useFullScreen:(NSNotification *)notification //use notification method and logic
{
NSString *key = @"fullScreen";
NSDictionary *dictionary = [notification userInfo];
BOOL boolValue;
if([dictionary valueForKey:key])
boolValue =[[dictionary valueForKey:key] boolValue];
}
【讨论】: