许多
Cocoa Touch类利用了合并事件的设计模式.例如,UIViews有一个方法setNeedsLayout,它可以在不久的将来调用layoutSubviews.这在许多属性影响布局的情况下尤其有用.在每个属性的setter中,您可以调用[self setNeedsLayout],这将确保布局将更新,但如果一次更改多个属性或者即使单个属性被修改多个,也会阻止对布局的许多(可能是昂贵的)更新运行循环的一次迭代中的时间.其他昂贵的操作,如setNeedsDisplay和drawRect:方法对遵循相同的模式.
实现这样的模式的最佳方法是什么?具体来说,我想将一些依赖属性绑定到一个昂贵的方法,如果属性发生了变化,每次迭代运行循环需要调用一次.
可能的解决方案:
使用CADisplayLink或NSTimer你可以得到这样的工作,但两者似乎都比必要的更多参与,我不确定将它添加到许多对象(尤其是计时器)的性能影响是什么.毕竟,性能是做这样的事情的唯一原因.
在某些情况下我使用过这样的东西:
- (void)debounceSelector:(SEL)sel withDelay:(CGFloat)delay { [NSObject cancelPrevIoUsPerformRequestsWithTarget:self selector:sel object:nil]; [self performSelector:sel withObject:nil afterDelay:delay]; }
这在用户输入应该仅在连续动作或类似事件时触发某些事件的情况下工作得很好.当我们想要确保触发事件没有延迟时,我们只想在同一个运行循环中合并调用,这似乎很笨拙.
解决方法
NSNotificationQueue就是你想要的东西.请参阅
Coalescing Notifications上的文档
这是UIViewController中的一个简单示例:
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(configureView:) name:@"CoalescingNotificationName" object:self]; [self setNeedsReload:@"viewDidLoad1"]; [self setNeedsReload:@"viewDidLoad2"]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self setNeedsReload:@"viewWillAppear1"]; [self setNeedsReload:@"viewWillAppear2"]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self setNeedsReload:@"viewDidAppear1"]; [self setNeedsReload:@"viewDidAppear2"]; } - (void)setNeedsReload:(NSString *)context { NSNotification *notification = [NSNotification notificationWithName:@"CoalescingNotificationName" object:self userInfo:@{@"context":context}]; [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName|NSNotificationCoalescingOnSender forModes:nil]; } - (void)configureView:(NSNotification *)notification { NSString *text = [NSString stringWithFormat:@"configureView called: %@",notification.userInfo]; NSLog(@"%@",text); self.detailDescriptionLabel.text = text; }
您可以签出文档并使用postingStyle来获取所需的行为.在此示例中,使用NSPostASAP将为我们提供输出:
configureView called: { context = viewDidLoad1; } configureView called: { context = viewDidAppear1; }
意味着已经合并了对setNeedsReload的背靠背调用.