我所从事的iOS应用程序配有一个Apple Watch应用程序。最近我们收到了一些关于GPS距离更新变慢的投诉,手表比手机慢几秒钟。我已经开始调查并编写了一些测试代码,来自[[WCSession defaultSession] sendMessage:message
replyHandler:replyHandler
errorHandler:errorHandler
的回复块在watchOS 2.2与2.1相比明显慢了一倍。我已经附上了测试代码。
#pragma mark - Location Update.
/**
* @description Provides an NSBlockOperation to be executed in an operation queue. This is an attempt to force serial
* processing
*/
- (NSBlockOperation*)distanceUpdateBlock {
NSBlockOperation *blockOp = [[NSBlockOperation alloc] init];
__weak NSBlockOperation * weakOp = blockOp;
__weak typeof(self) weakSelf = self;
[blockOp addExecutionBlock:^{
typeof(weakSelf) blockSafeSelf = weakSelf;
typeof(weakOp) blockSafeOp = weakOp;
if (!blockSafeOp.isCancelled) { // Make sure we haven't already been cancelled.
__block NSDate *startDate = [NSDate date];
__block BOOL completed = NO;
void (^replyBlock)(NSDictionary*) = ^(NSDictionary *message){
if (!blockSafeOp.isCancelled) {
[blockSafeSelf processUserLocationOnWatch:message];
double replyTime = [[NSDate date] timeIntervalSinceDate:startDate];
NSLog(@"Reply Time: %.03f", replyTime);
completed = YES;
}
};
void (^failBlock)(NSError*) = ^(NSError *error) {
if (!blockSafeOp.isCancelled) {
double replyTime = [[NSDate date] timeIntervalSinceDate:startDate];
NSLog(@"Reply Time Fail: %.03f", replyTime);
completed = YES;
}
};
[self fetchUserLocationFromIphoneWithReplyHandler:replyBlock errorHandler:failBlock];
do {
usleep(10000); // 1/100th second wait to throttle evaluations (Don't worry - in final code I will subclass NSOperation and control when it actually finishes - this is for easy testing.)
} while (!completed && !blockSafeOp.isCancelled && [blockSafeSelf isWatchReachable]); //(isWatchReachable just makes sure we have a session with the phone and it is reachable).
}
}];
blockOp.completionBlock = ^{
typeof(weakSelf) blockSafeSelf = weakSelf;
typeof(weakOp) blockSafeOp = weakOp;
if (!blockSafeOp.isCancelled) {
[blockSafeSelf addOperationForLocationUpdate]; // since we are finished - add another operation.
}
};
return blockOp;
}
- (void)addOperationForLocationUpdate {
[distanceUpdateOperationQueue addOperation:[self distanceUpdateBlock]];
}
- (void)startUpdatingLocation {
[self addOperationForLocationUpdate];
}
- (void)stopUpdatingLocation {
[distanceUpdateOperationQueue cancelAllOperations];
}
- (void)fetchUserLocationFromIphoneWithReplyHandler:(nullable void (^)(NSDictionary<NSString *, id> *replyMessage))replyHandler errorHandler:(nullable void (^)(NSError *error))errorHandler {
if (self.isSessionActive) {
NSDictionary *message = @{kWatchSessionMessageTag:kWatchSessionMessageUserLocation};
if (self.isWatchReachable) {
[[WCSession defaultSession] sendMessage:message
replyHandler:replyHandler
errorHandler:errorHandler
];
} else {
errorHandler(nil);
}
} else {
[self activateSession];
errorHandler(nil);
}
}
iPhone端的处理程序仅获取用户位置并使用编码信息调用replyHandler。
2.2版本的时间日志看起来是这样的(大约一秒钟)
回复时间:0.919
回复时间:0.952
回复时间:0.991
回复时间:0.981
回复时间:0.963
相同的代码在2.1上如下:
回复时间:0.424
回复时间:0.421
回复时间:0.433
回复时间:0.419
此外,我注意到5分钟(300秒)后,那些已经调用了回复处理程序的消息将开始调用错误处理程序。我看到另一个线程中有人也提到了这一点,还有其他人遇到过这种情况并知道原因吗?
因此,问题1 - 是否有人遇到了这种性能减慢并找到了保持replyHandler运行更快或找到更快的更新方式的解决方法?
问题2 - errorHandler在5分钟后被调用的解决方案。
只有一些要排除的事情 - 我已经尽了我的责任,在接收消息和调用replyHandler之间测试了iOS代码。 在iOS 9.2 / 9.3之间处理时间没有变化。 我把它缩小到了这个调用。 实际上,我们以前的版本是现在备份sendMessage的操作队列。所以现在我正在使用这个测试代码强制进行一次调用。 现在我们不再被拥堵,但是单个调用很慢。