【发布时间】:2016-03-22 01:56:29
【问题描述】:
我知道当 Apple 不推荐后台应用程序时更新 UI,尤其是对于 OpenGL。
但是,我刚刚意识到 iMessenger 和 Facebook 的 Messenger 看起来可以做到这一点。和你的朋友输入一个消息线程然后去后台,然后在应用还在后台的时候收到一条新消息,然后把这个应用带到前台(点击推送通知或应用图标),你会发现新消息气泡是已经有来自图标的应用扩展动画。
据我了解,这只会发生,因为新消息气泡已经在后台模式下绘制。然后当应用进入前台时,它可以出现在动画中。
但是从我的测试结果来看,在 iOS8 和 iOS9 中,所有的后台 UI 更新都会在应用激活后推迟。此外,iOS 将为该 UI 更新添加一个隐式动画事务。
我在下面列出了我的测试代码,当应用程序进入前台时,您会看到新单元格被添加到表格中,并带有明显的动画事务,这与 iMessenger 完全不同。 tableView:numberOfRowsInSection: 只会在应用进入前台时延迟执行。
而且不只是tableview单元格更新,即使在后台添加子视图也会触发类似的延迟事务进入前台。
也许我在这方面的方向完全错误。谁能帮助我了解 iMessenger 和 FB 的 Messenger 是如何实现这种效果的? 提前致谢!
@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic) UITableView *tableView;
@property (nonatomic) NSMutableArray *dataTable;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.tableView];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:@"kCellId"];
self.dataTable = [[NSMutableArray alloc] initWithArray:@[@"1", @"2", @"3"]];
__weak __typeof(self) weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
[weakSelf.dataTable addObject:[@(weakSelf.dataTable.count + 1) stringValue]];
[weakSelf.tableView reloadData];
});
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataTable.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"kCellId"];
cell.textLabel.text = self.dataTable[indexPath.row];
return cell;
}
@end
【问题讨论】:
-
你为什么使用
dispatch_after?这迫使等待一个运行循环并稍后执行该块 - 在屏幕已经绘制一次之后。 NSNotificationCenter 实际上总是 在主线程中调用它的观察者。这意味着您根本不必使用 GCD。尝试删除dispatch_after调用。 -
使用 dispatch_after 是在后台尝试模拟更新 UI。确实进入后台通知后直接调用 UI update 不能保证核心动画已经停止。
-
我建议不要对这样的测试用例进行硬编码。如果您想要更好的测试,我会向您的应用发送推送通知,其中包含一些任意数据。当应用收到推送通知时,使用从推送通知收到的数据更新 dataTable。
标签: ios user-interface animation