有没有其他人注意到并发症条目没有正确更新的问题。我刚刚为我的应用程序添加了一些初始支持,但注意到它们没有显示我期望它们显示的内容。例如,为了方便快速测试这个问题,我会创建一个时间线
A -> B -> C
0s 10s 20s
然而,我所看到的只是并发症条目 A 停留在 B 和 C 应该显示的时间之后。
我的普通应用程序本身并没有设置为像这样创建定期间隔的并发症,它具有可以由用户设置的计时器的许多方面,但其中一个方面只是允许用户一次启动多个计时器,这一切将在他们选择的用户定义的持续时间后完成。与 iOS 时钟应用程序的计时器不同,您可以以秒为单位指定计时器持续时间,因此 2 个计时器完全有可能在几秒钟内完成,但总体而言,它们更有可能相隔几分钟。此外,不应该添加太多的复杂条目,尽管我的应用程序的其他更复杂的方面可以轻松添加 10 甚至 100 个复杂条目,具体取决于用户在其中设置的任务的复杂程度。不过就目前而言,
我将 Xcode 更新到了最新版本(7.3.2),没有任何改进,并将构建发送到我的实际手机和手表,同样没有改进。直到它确实起作用了。在进一步的调试中,我发现我可以通过简单地降低我的手表(关闭屏幕)然后再次唤醒它来使时间线自动运行,而这一切都是在它正在执行我的时间线的过程中进行的。完成此操作后,时间线将从那时起正常工作。
我创建了一个测试应用程序来演示该问题,它确实完全重现了该问题,因此我将在错误报告中将其发送给苹果。只是想看看有没有其他人注意到这个问题。
此外,当我的测试应用程序执行时,我得到以下日志输出,其中包含一个没有意义的错误
-[ExtensionDelegate session:didReceiveUserInfo:]:67 - complication.family=1 in activeComplications - calling reloadTimelineForComplication
-[ComplicationController getTimelineStartDateForComplication:withHandler:]:43 - calling handler for startDate=2016-06-15 22:08:26 +0000
-[ComplicationController getTimelineEndDateForComplication:withHandler:]:73 - calling handler for endDate=2016-06-15 22:08:46 +0000
-[ComplicationController getCurrentTimelineEntryForComplication:withHandler:]:148 - calling handler for entry at date=2016-06-15 22:08:26 +0000
-[ComplicationController getTimelineEntriesForComplication:afterDate:limit:withHandler:]:202 - adding entry at date=2016-06-15 22:08:36 +0000; with timerEndDate=2016-06-15 22:08:46 +0000 i=1
getTimelineEntriesForComplication:afterDate:limit:withHandler: -- invalid entries returned. (1 entries before start date 2016-06-15 22:08:46 +0000). Excess entries will be discarded.
该日志的相关信息如下
getTimelineStartDateForComplication - calling handler for startDate=22:08:26
getTimelineEndDateForComplication - calling handler for endDate=22:08:46
getCurrentTimelineEntryForComplication - calling handler for entry at date=22:08:26
getTimelineEntriesForComplication:afterDate - adding entry at date=22:08:36
getTimelineEntriesForComplication:afterDate:limit:withHandler: -- invalid entries returned. (1 entries before start date 22:08:46). Excess entries will be discarded.
您可以在最后的系统错误中看到它使用22:08:46的开始日期,这实际上是我告诉 Clockkit 的是我的时间线的 endDate,而不是startDate。我不确定这是否与我看到的行为有关,因为我在隐藏/显示屏幕后看到相同的错误。
我在我的在线测试应用程序中放了一段关于这种行为的视频。此测试应用程序的详细信息如下
应该在相关模拟器中运行的完整代码在这里可用,相关的复杂模块也在这里列出以供参考。
在我的扩展委托中,我从 iOS 应用程序接收 userInfo 并安排重新加载我的并发症时间线
ExtensionDelegate.m
- (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *, id> *)userInfo
{
DbgLog(@"");
WKExtension *extension = [WKExtension sharedExtension];
DbgLog(@"self=%p; wkExtension=%p; userInfo=%@", self, extension, userInfo);
self.lastReceivedUserInfo = userInfo;
CLKComplicationServer *complicationServer = [CLKComplicationServer sharedInstance];
for (CLKComplication *complication in complicationServer.activeComplications)
{
DbgLog(@"complication.family=%d in activeComplications - calling reloadTimelineForComplication", complication.family);
[complicationServer reloadTimelineForComplication:complication];
}
}
然后在我的 ComplicationController 中有以下方法来处理事情的复杂性
并发症控制器.m
#define DbgLog(fmt, ...) NSLog((@"%s:%d - " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
@interface ComplicationController ()
@end
@implementation ComplicationController
#pragma mark - Timeline Configuration
- (void)getSupportedTimeTravelDirectionsForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTimeTravelDirections directions))handler
{
handler(CLKComplicationTimeTravelDirectionForward|CLKComplicationTimeTravelDirectionBackward);
}
- (void)getTimelineStartDateForComplication:(CLKComplication *)complication withHandler:(void(^)(NSDate * __nullable date))handler
{
NSDate *startDate;
WKExtension *extension = [WKExtension sharedExtension];
assert(extension.delegate);
assert([extension.delegate isKindOfClass:[ExtensionDelegate class]]);
ExtensionDelegate *extensionDelegate = (ExtensionDelegate *)extension.delegate;
if (extensionDelegate.lastReceivedUserInfo)
{
NSDictionary *userInfo = extensionDelegate.lastReceivedUserInfo;
startDate = [userInfo objectForKey:@"date"];
}
DbgLog(@"calling handler for startDate=%@", startDate);
handler(startDate);
}
- (NSDate*)getTimelineEndDate
{
NSDate *endDate;
WKExtension *extension = [WKExtension sharedExtension];
assert(extension.delegate);
assert([extension.delegate isKindOfClass:[ExtensionDelegate class]]);
ExtensionDelegate *extensionDelegate = (ExtensionDelegate *)extension.delegate;
if (extensionDelegate.lastReceivedUserInfo)
{
NSDictionary *userInfo = extensionDelegate.lastReceivedUserInfo;
NSDate *startDate = [userInfo objectForKey:@"date"];
NSNumber *duration = [userInfo objectForKey:@"duration"];
NSNumber *count = [userInfo objectForKey:@"count"];
NSTimeInterval totalDuration = duration.floatValue * count.floatValue;
endDate = [startDate dateByAddingTimeInterval:totalDuration];
}
return endDate;
}
- (void)getTimelineEndDateForComplication:(CLKComplication *)complication withHandler:(void(^)(NSDate * __nullable date))handler
{
NSDate *endDate=[self getTimelineEndDate];
DbgLog(@"calling handler for endDate=%@", endDate);
handler(endDate);
}
- (void)getPrivacyBehaviorForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationPrivacyBehavior privacyBehavior))handler {
handler(CLKComplicationPrivacyBehaviorShowOnLockScreen);
}
#pragma mark - Timeline Population
- (CLKComplicationTemplate *)getComplicationTemplateForComplication:(CLKComplication *)complication
forEndDate:(NSDate *)endDate
orBodyText:(NSString *)bodyText
withHeaderText:(NSString *)headerText
{
assert(complication.family == CLKComplicationFamilyModularLarge);
CLKComplicationTemplateModularLargeStandardBody *template = [[CLKComplicationTemplateModularLargeStandardBody alloc] init];
template.headerTextProvider = [CLKSimpleTextProvider textProviderWithText:headerText];
if (endDate)
{
template.body1TextProvider = [CLKRelativeDateTextProvider textProviderWithDate:endDate style:CLKRelativeDateStyleTimer units:NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond];
}
else
{
assert(bodyText);
template.body1TextProvider = [CLKSimpleTextProvider textProviderWithText:bodyText];
}
return template;
}
- (CLKComplicationTimelineEntry *)getComplicationTimelineEntryForComplication:(CLKComplication *)complication
forStartDate:(NSDate *)startDate
endDate:(NSDate *)endDate
orBodyText:(NSString *)bodyText
withHeaderText:(NSString *)headerText
{
CLKComplicationTimelineEntry *entry = [[CLKComplicationTimelineEntry alloc] init];
entry.date = startDate;
entry.complicationTemplate = [self getComplicationTemplateForComplication:complication forEndDate:endDate orBodyText:bodyText withHeaderText:headerText];
return entry;
}
- (void)getCurrentTimelineEntryForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTimelineEntry * __nullable))handler
{
// Call the handler with the current timeline entry
CLKComplicationTimelineEntry *entry;
assert(complication.family == CLKComplicationFamilyModularLarge);
WKExtension *extension = [WKExtension sharedExtension];
assert(extension.delegate);
assert([extension.delegate isKindOfClass:[ExtensionDelegate class]]);
ExtensionDelegate *extensionDelegate = (ExtensionDelegate *)extension.delegate;
if (extensionDelegate.lastReceivedUserInfo)
{
NSDictionary *userInfo = extensionDelegate.lastReceivedUserInfo;
NSDate *startDate = [userInfo objectForKey:@"date"];
NSNumber *duration = [userInfo objectForKey:@"duration"];
//NSNumber *count = [userInfo objectForKey:@"count"];
NSTimeInterval totalDuration = duration.floatValue;
NSDate *endDate = [startDate dateByAddingTimeInterval:totalDuration];
entry = [self getComplicationTimelineEntryForComplication:complication forStartDate:startDate endDate:endDate orBodyText:nil withHeaderText:@"current"];
}
if (!entry)
{
NSDate *currentDate = [NSDate date];
entry = [self getComplicationTimelineEntryForComplication:complication forStartDate:currentDate endDate:nil orBodyText:@"no user info" withHeaderText:@"current"];
}
DbgLog(@"calling handler for entry at date=%@", entry.date);
handler(entry);
}
- (void)getTimelineEntriesForComplication:(CLKComplication *)complication beforeDate:(NSDate *)date limit:(NSUInteger)limit withHandler:(void(^)(NSArray<CLKComplicationTimelineEntry *> * __nullable entries))handler
{
NSArray *retArray;
assert(complication.family == CLKComplicationFamilyModularLarge);
WKExtension *extension = [WKExtension sharedExtension];
assert(extension.delegate);
assert([extension.delegate isKindOfClass:[ExtensionDelegate class]]);
ExtensionDelegate *extensionDelegate = (ExtensionDelegate *)extension.delegate;
if (extensionDelegate.lastReceivedUserInfo)
{
NSDictionary *userInfo = extensionDelegate.lastReceivedUserInfo;
NSDate *startDate = [userInfo objectForKey:@"date"];
if ([startDate timeIntervalSinceDate:date] < 0.f)
{
assert(0);
// not expected to be asked about any date earlier than our startDate
}
}
// Call the handler with the timeline entries prior to the given date
handler(retArray);
}
- (void)getTimelineEntriesForComplication:(CLKComplication *)complication afterDate:(NSDate *)date limit:(NSUInteger)limit withHandler:(void(^)(NSArray<CLKComplicationTimelineEntry *> * __nullable entries))handler
{
NSMutableArray *timelineEntries = [[NSMutableArray alloc] init];
assert(complication.family == CLKComplicationFamilyModularLarge);
WKExtension *extension = [WKExtension sharedExtension];
assert(extension.delegate);
assert([extension.delegate isKindOfClass:[ExtensionDelegate class]]);
ExtensionDelegate *extensionDelegate = (ExtensionDelegate *)extension.delegate;
if (extensionDelegate.lastReceivedUserInfo)
{
NSDictionary *userInfo = extensionDelegate.lastReceivedUserInfo;
NSDate *startDate = [userInfo objectForKey:@"date"];
NSNumber *duration = [userInfo objectForKey:@"duration"];
NSNumber *count = [userInfo objectForKey:@"count"];
NSInteger i;
for (i=0; i<count.integerValue && timelineEntries.count < limit; ++i)
{
NSTimeInterval entryDateOffset = duration.floatValue * i;
NSDate *entryDate = [startDate dateByAddingTimeInterval:entryDateOffset];
if ([entryDate timeIntervalSinceDate:date] > 0)
{
NSDate *timerEndDate = [entryDate dateByAddingTimeInterval:duration.floatValue];
DbgLog(@"adding entry at date=%@; with timerEndDate=%@ i=%d", entryDate, timerEndDate, i);
CLKComplicationTimelineEntry *entry = [self getComplicationTimelineEntryForComplication:complication forStartDate:entryDate endDate:timerEndDate orBodyText:nil withHeaderText:[NSString stringWithFormat:@"After %d", i]];
[timelineEntries addObject:entry];
}
}
if (i==count.integerValue && timelineEntries.count < limit)
{
NSDate *timelineEndDate = [self getTimelineEndDate];
CLKComplicationTimelineEntry *entry = [self getComplicationTimelineEntryForComplication:complication forStartDate:timelineEndDate endDate:nil orBodyText:@"Finished" withHeaderText:@"Test"];
[timelineEntries addObject:entry];
}
}
NSArray *retArray;
if (timelineEntries.count > 0)
{
retArray = timelineEntries;
}
// Call the handler with the timeline entries after to the given date
handler(retArray);
}
#pragma mark Update Scheduling
/*
// don't want any updates other than the ones we request directly
- (void)getNextRequestedUpdateDateWithHandler:(void(^)(NSDate * __nullable updateDate))handler
{
// Call the handler with the date when you would next like to be given the opportunity to update your complication content
handler(nil);
}
*/
- (void)requestedUpdateBudgetExhausted
{
DbgLog(@"");
}
#pragma mark - Placeholder Templates
- (void)getPlaceholderTemplateForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTemplate * __nullable complicationTemplate))handler
{
CLKComplicationTemplate *template = [self getComplicationTemplateForComplication:complication forEndDate:nil orBodyText:@"doing nothing" withHeaderText:@"placeholder"];
// This method will be called once per supported complication, and the results will be cached
handler(template);
}
@end
也许你可以看看你自己的应用程序是否有同样的问题。
我不认为我做错了什么,没有什么会导致这种奇怪的行为,对我来说就像一个错误。不幸的是,它破坏了我的应用程序,该应用程序在某些情况下可以使用非常小的时间线条目,如果用户注意并在测试时保持手表屏幕打开,我宁愿不让它们不起作用。
谢谢你的时间,
干杯