【发布时间】:2016-06-29 22:09:04
【问题描述】:
我使用的 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 秒)后,错误处理程序开始在已调用回复处理程序的消息上被调用。我看到另一个帖子也有人提到了这一点,还有其他人发生这种情况并知道为什么吗?
那么,Q1 - 有没有人遇到这种性能下降并想出如何让 replyHandler 运行得更快,或者找到更快的方法来获取更新?
Q2 - errorHandler 在 5 分钟后被调用的解决方案。
只需消除几件事 - 我已经尽职尽责地测试了在接收消息和调用 replyHandler 之间的 iOS 代码。 iOS 9.2/9.3 之间的处理时间没有变化。我已经把它缩小到这个电话。事实上,我们在以前的版本中这样做的方式现在是备份 sendMessage 的 operationQueue。所以现在我强制使用这个测试代码一次调用一个。我们不再得到备份,但个别调用速度很慢。
【问题讨论】: