天道酬勤,学无止境

获取数据复杂化:未调用 ExtensionDelegate(Get Data to Complication: ExtensionDelegate not Called)

问题

(看起来这个问题在前几周已经被其他人遇到了,但我还没有找到任何解决方案。)

我正在尝试做一件非常基本的事情:从我的 iOS 应用程序或我的 Watch 应用程序获取数据到我的 Complication Controller。

事实证明,我完成这件事的能力比我想象的要差得多。 watchOS 2 Transition Guide 指出我应该使用以下代码“[获取]来自扩展委托的所需数据”:

ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];  
NSDictionary* data = [myDelegate.myComplicationData objectForKey:ComplicationCurrentEntry];

伟大的。 除了,我一直无法弄清楚如何让它在扩展端工作。 尽管更重要的是,我似乎甚至无法从复杂控制器启动中运行扩展委托代码。 当我运行复杂功能时,我收到以下消息:“扩展收到唤醒复杂功能支持的请求。” 但是,任何扩展委托的方法中的代码似乎都没有运行。 我还在每个方法中设置了断点,并且没有一个断点被命中。

它看起来也像“transferCurrentComplicationUserInfo:”也被建议用于复杂功能更新,尽管目前还不清楚它是如何使用的。 据我所知,它用于唤醒手表扩展,以便 ExtensionDelegate 可以在下次运行复杂控制器时存储新数据,但由于之前的问题,我无法确认。

我有一个可能的解决方法(从复杂性控制器 ping 服务器并希望会话变量持续存在,以便我可以发送相关数据),但是如果我无法解决这个问题,我的复杂性工作很有可能会失败。 这里的任何帮助都将是巨大的。

顺便说一句,这是我的“getCurrentTimelineEntryForComplication”代码,如果这有帮助的话。

- (void)getCurrentTimelineEntryForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTimelineEntry * __nullable))handler {  
    NSDate* entryDate = [NSDate date];  

    ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];  
    NSString* data = [myDelegate.complicationData objectForKey:@"meow"];  
    NSLog(@"complication data: %@", data);  

    CLKComplicationTimelineEntry* entry = [self getTimelineEntry:@"2015-08-25 00:19:42" entryDate:entryDate complication:complication];  

    handler(entry);  
}
回答1

自 Xcode 7 Beta 4 以来,我一直在 WatchOS2 中使用 Complications。我现在使用的是最新的 Xcode Beta 6。我遇到了许多问题,例如在 Watch 上运行的两个 Beta 版本,然后在 iPhone 上运行安装到 Watch 并在模拟器上运行,由于 API 和操作系统版本似乎有问题,经常会出现误报。 我已经能够通过以下方式获取数据以显示并发症。

  • 确保您的主接口控制器实现 WCSessionDelegate 协议。
  • 实现你的接口控制器的didReceiveMessage和didReceiveApplicationContext方法两者
  • 在您的 iPhone 应用程序中,尝试使用 WCSession 向手表发送消息。
  • 如果消息无法从 iPhone 应用程序发送,请发送应用程序上下文。
  • 返回接口控制器,当您收到消息或上下文时,更新扩展委托中的值。
  • 仍然在接口控制器中并且仍然在收到消息或上下文后,获取 CLKComplicationServer 的句柄,并为 activeComplications 中的每个复杂功能调用 reloadTimelineForComplication。
  • 在您的 Complication Controller 的 getCurrentTimelineEntryForComplication 中,获取您在 Extension Delegate 中设置的数据并在您的 CLKComplicationTimelineEntry 中设置值。
  • 当应用程序已经在 Watch 上打开时,这通常会起作用,该应用程序仍然驻留在内存中,但在 Watch 上运行,或者您启动应用程序并且它们正在等待它消耗的上下文。
  • 我无法让历史时间线条目发挥作用(或未来的)。 我也无法独立于 Watch 应用程序获取更新时间线。

如果您遇到问题,可以尝试以下调试方法。 正如我上面所说,API 和操作系统似乎有很多问题。 以下步骤确实有效(有时)。

  • 在 sim 中,使用 iPhone 和 Watch sim 上的重置所有设置选项。
  • 在设备上,重新启动 Watch。 如有必要,请取消配对并修理手表,尽管这需要很长时间才能完成。
  • 在 iPhone 上,删除该应用程序(如果已安装,也会删除 Watch 应用程序)并重新安装。

我希望这有帮助!

贾斯汀

回答2

为了使 ComplicationController 响应 WCSession 活动,您必须使控制器符合 WCSessionDelegate,然后从 ComplicationController 中管理 didReceiveUserInfo。 在后台时,不会为这些更新唤醒 ExtensionDelegate。 如有必要,您仍然可以从控制器更新您的委托。

此外,截至目前,模拟器不会将 transferCurrentComplicationUserInfo 发送到手表模拟器,您必须在设备上进行测试。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 调用ExtensionDelegate来创建/刷新用于并发症的数据(Call ExtensionDelegate to create/refresh data for Complication)
    问题 我所有的数据创建都在ExtensionDelegate.swift完成。 问题是我的ComplicationController.swift getCurrentTimelineEntryForComplication函数之前没有调用ExtensionDelegate.swift 。 有任何想法吗? 这是我的代码和详细信息: 因此,我的ComplicationController.swift数组extEvnts为空: func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) { let extEvnts = ExtensionDelegate.evnts } 因为尚未调用我的ExtensionDelegate.swift ,所以将为数组创建数据: class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { private let session = WCSession.defaultSession() var receivedData = Array
  • WatchKit Complication:从扩展委托获取并发症数据(WatchKit Complication: get Complication data from extension delegate)
    问题 我的 WatchKit 扩展中有我需要的所有数据(从 iOS 应用程序传递)。 我用WatchKit InterfaceController的数据填了一张表格,效果很好。 我试图找出在我的 WatchKit ComplicationController获取相同数据的最佳方法。 目前,在InterfaceController ,数据使用didReceiveUserInfo传入: func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) { if let beachValue = userInfo["Surf"] as? String { places.append(Place(dataDictionary: ["Surf" : surfValue])) } else { print("Something went wrong") } } 我是否需要在我的ComplicationController调用这个相同的WCSession方法并再次抓取整个数据,或者有没有更简单的方法让我访问在ComplicationController使用的相同数据? 任何帮助表示赞赏。 谢谢! 编辑: 我的表功能: func makeTable() { // Per SO let
  • Get Data to Complication: ExtensionDelegate not Called
    (It looks like this issue has been encountered by others in previous weeks, but there haven't been any solutions that I've found.) I'm trying to do a really basic thing: Get data from either my iOS app or my Watch app to my Complication Controller. I am turning out to be way less capable of getting this done than I thought. watchOS 2 Transition Guide indicates that I should "[fetch] the needed data from the extension delegate" using the following code: ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate]; NSDictionary* data = [myDelegate.myComplicationData objectForKey
  • Call ExtensionDelegate to create/refresh data for Complication
    All my data creation is done in the ExtensionDelegate.swift. The problem is ExtensionDelegate.swift doesn't get called before the function getCurrentTimelineEntryForComplication in my ComplicationController.swift. Any ideas? Here is my code and details: So my array extEvnts is empty in my ComplicationController.swift: func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) { let extEvnts = ExtensionDelegate.evnts } Because my ExtensionDelegate.swift hasn't gotten called yet, which is what creates the data for
  • Keeping my WatchKit complications up to date when not running
    I'm working on the WatchKit Extension of my app, and have some issues with complications. I have a complication that displays a given total amount, which depends of what the user is doing on the iOS app. When the WatchKit Extension is running, the iOS app updates the watch app context using the -[WCSession updateApplicationContext:] method. It works fine, and then in the ExtensionDelegate of my Watch app, I manually update the complication with the new data. But this is OK only when the extension is running (if it's not, it won't get the application context until the next launch). So I edited
  • 何时何地获取手表并发症数据(Where and When to get data for Watch Complication)
    问题 在处理了几天的复杂性之后,我有信心说出以下有关在规定间隔内发生的更新的更新过程: 系统调用requestedUpdateDidBegin() 在这里,您可以确定数据是否已更改。 如果没有,则您的应用程序无需执行任何操作。 如果您的数据已更改,则需要调用以下任一方法: reloadTimelineForComplication如果需要重置所有数据)。 如果您只需要在复杂时间线的末尾添加新项目,则可以使用extendTimelineForComplication 。 注意:如果您当天花费了太多的并发症时间预算,则系统实际上可能会调用requestedUpdateBudgetExhausted()而不是requestedUpdateDidBegin() 。 这就是这个问题的原因。 如果您调用了reloadTimelineForComplication ,则系统将调用getCurrentTimelineEntryForComplication (以及将来和过去获取数组的变体,具体取决于您的时间旅行设置) 这是一个猜测,因为我尚未对其进行测试,但是我相信,如果您调用了extendTimelineForComplication ,则只会调用getTimelineEntriesForComplication(... afterDate date: NSDate ...) 。 然后
  • 如何正确实现从 iOS 应用程序到 watchOS2 并发症的设置传输(How to correctly implement transfer of settings from iOS app to watchOS2 complication)
    问题 我想要实现的是以下内容: 复杂功能每隔 30 分钟在后台更新一次每当手表应用程序运行并接收到自己的更新数据时,并发症就会更新每当 iOS 应用程序运行并且用户更改影响手表数据的设置(例如更改天气观测的位置或显示单位)时,并发症就会更新 第 1 项和第 2 项似乎很简单,在这里得到了很好的解决:更新 Apple Watch 复杂功能数据的流程是什么? 但是,对于第 3 项,在 iOS 应用程序中,我设置了一个 WCSession 实例并调用 transferCurrentComplicationUserInfo,将新设置作为 NSDictionary 发送。 在 watch 扩展中,这会调用 WCSessionDelegate 中的 didReceiveUserInfo。 - (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *,id> *)userInfo { // Code here to apply the new settings // .... // Invoke a NSUSRLSession-based web query to get new data [self queryForNewDataWithCompletionHandler:^
  • 更新Apple Watch并发症数据的流程是什么?(What is the flow for updating complication data for Apple Watch?)
    问题 我一直在互联网上关注许多教程,以学习如何设置并发症。 我可以按预期设置并发症。 直到初始时间轴条目到期。 12小时后,我不知道如何对其进行更新以使并发症持续存在。 我将分享我下面的所有内容,希望有人可以帮助我填写。 在这里,我为要在复杂情况下显示的数据创建了变量。 struct data = { var name: String var startString: String var startDate: NSDate } 以下数组是此数据的容器。 var dataArray = [data] 这样可以在手表锁定时显示复杂情况。 func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) { handler(.ShowOnLockScreen) } 这样就可以在复杂情况下进行时间旅行。 func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) ->
  • Apple Watch 复杂功能未在后台更新(Apple Watch Complication not updating in background)
    问题 我有一个 Apple Watch 并发症,它可以正确初始化并显示我期望的数据。 但是,当我的 getNextRequestedUpdateDateWithHandler 方法中返回的 NSDate 触发刷新时,我的委托中唯一被再次调用的方法是 getNextRequestedUpdateDateWithHandler 方法(我在每个方法上设置断点来确定这一点)。 我本来希望在请求的更新日期发生时调用 requestsUpdateDidBegin,但情况似乎并非如此。 有谁知道是什么原因造成的? 这是我的代码: class ComplicationController: NSObject, CLKComplicationDataSource { /// Provide the time travel directions your complication supports (forward, backward, both, or none). func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) { handler(
  • watchOS - 显示有关并发症的实时出发数据(watchOS - Show realtime departure data on complication)
    问题 我有一个公共交通应用程序,其中包含火车的实时出发数据。 我想添加一个显示下一班火车出发时间的复杂功能。 是否可以显示(或刷新)复杂功能的实时数据? 例如,显示“3 分钟到 X 站”。 根据来自公共交通 API 的信息,数据可能每分钟都在变化。 我应该如何在 watchOS 2 或 watchOS 3 上完成此操作? 我知道 ETA 应用程序以复杂的方式显示旅行时间,但我不确定它们是如何实现的。 回答1 可以实时更新吗? 复杂功能并非旨在显示实时数据。 频繁更新会影响能源效率并影响电池(在手表和手机上)。 为了最大限度地减少功耗,ClockKit 要求您提供尽可能多的可用数据,然后缓存数据并在需要时呈现它。 虽然没有固定次数的复杂时间线可以重新加载,但复杂数据源受每日执行时间预算的约束。 如果您的应用程序的数据频繁更改,则可能难以提供足够的数据以在复杂情况下显示。 更糟糕的是,如果您过于频繁地刷新复杂功能数据,您可能会超出执行时间预算,并且您的复杂功能可能要到第二天才会更新。 一旦每日预算用完,对 reloadTimeline(和 extendTimeline)的调用就什么都不做。 如果您的复杂功能已超过其分配的每日执行时间预算,则调用此方法将无济于事。 谨慎调用此方法。 复杂功能如何显示相对时间? 您可以使用 CLKRelativeDateTextProvider
  • 结合 WatchConnectivity 和复杂功能(Combining WatchConnectivity and Complications)
    问题 我希望我的复杂功能通过 Watch Connectivity 从 iPhone 获取数据。 我正在使用sendMessage即时消息技术。 当我尝试获取数据时,我不希望我的 iPhone 应用程序打开,因此这需要在后台运行。 在我的 iPhone 上的 ViewController 中: import UIKit import WatchConnectivity class ViewController: UIViewController, WCSessionDelegate { var session: WCSession! override func viewDidLoad() { super.viewDidLoad() if WCSession.isSupported() { self.session = WCSession.defaultSession() self.session.delegate = self self.session.activateSession() } } func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) { if message
  • WatchKit Complication: get Complication data from extension delegate
    I have all the data I need in my WatchKit Extension (passed from the iOS app). I used the data in the WatchKit InterfaceController to fill in a table, which works perfectly. I'm trying to figure out the best way to get that same data in my WatchKit ComplicationController. Currently, in the InterfaceController, the data gets passed in using didReceiveUserInfo: func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) { if let beachValue = userInfo["Surf"] as? String { places.append(Place(dataDictionary: ["Surf" : surfValue])) } else { print("Something went wrong") } }
  • transferCurrentComplicationUserInfo是否更适合并发症更新?(Is transferCurrentComplicationUserInfo more suitable for complication update?)
    问题 transferCurrentComplicationUserInfo和transferUserInfo什么区别? 我想将数据从AppDelegate发送到时钟套件并发症。 transferCurrentComplicationUserInfo似乎做同样的事情transferCurrentUserInfo 。 我想念什么吗? 回答1 这两个WCSession方法之间的区别涉及何时发送数据以及是否唤醒了watchkit扩展。 transferCurrentComplicationUserInfo:专门用于传输要在表盘上立即显示的复杂用户信息。 复杂用户信息标记为“紧急”,并位于队列的最前面, 手表会在后台唤醒该扩展程序以接收信息,并且转移立即发生。 (其他排队的信息也可能会在此时转移。) transferUserInfo:将信息排队,在系统确定是处理队列的适当时机将要传输的信息: 用户信息位于队列的后面, 如果扩展名未唤醒,则存储已传输的信息, 转移不会立即发生,并且信息将按照其发送顺序进行传递。 有关更多详细信息,请参阅WWDC 2015介绍手表连接性的视频。 iOS 10更新: 在iOS 10中, WCSession添加了剩余的WCSession属性,该属性可能会影响iOS将使用哪种方法来传输用户信息:
  • WatchKit 中 UIApplication.sharedApplication().delegate 的等价物是什么?(What is the equivalent of UIApplication.sharedApplication().delegate in WatchKit?)
    问题 在 iOS 应用程序中,您可以通过以下方式获取对共享应用程序委托的引用: 迅速: let delegate = UIApplication.sharedApplication().delegate as! AppDelegate 目标-C: AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; 在 WatchKit2 App Extension 中有一个类似的 App Delegate,我想在视图控制器中获取对它的引用,以访问应用程序中的共享资源,例如核心数据堆栈的 ManagedObjectModel 和 PersistentStoreCoordinator,我已在应用代理。 但是, UIApplication.sharedApplication().delegate as! AppDelegate UIApplication.sharedApplication().delegate as! AppDelegate报错, 使用未解析的标识符“UIApplication” 如何访问 WatchKit2 应用扩展中的应用委托? 回答1 WatchOS 2 中的WKExtension类自动为每个扩展提供一个扩展对象,以管理在所有应用程序界面控制器之间共享的行为。 Apple 文档指出,您
  • Watchkit 并发症和位置更新?(Watchkit Complication and location updates?)
    问题 我正在尝试编写一个使用位置数据的复杂功能。 我可以在复杂控制器中获取位置数据,但由于结果异步返回,它似乎永远无法正常工作。 使用特定于位置的数据更新复杂功能的最佳方法是什么? 我认为在并发症中获取位置不是一个好主意(即使你可以)。 回答1 您应该在复杂数据源需要位置数据之前检索和缓存位置数据。 数据源类的工作是尽快为 ClockKit 提供任何请求的数据。 数据源方法的实现应该是最少的。 不要使用您的数据源方法从网络获取数据、计算值或做任何可能会延迟数据交付的事情。 如果您需要为您的复杂功能获取或计算数据,请在您的 iOS 应用程序或 WatchKit 扩展的其他部分执行此操作,并将数据缓存在您的复杂功能数据源可以访问它的位置。 您的数据源方法唯一应该做的就是获取缓存的数据并将其放入 ClockKit 所需的格式。 您可以在手机上检索位置数据,然后使用手表连接会话将transferCurrentComplicationUserInfo到您的分机委托。 扩展委托可以缓存复杂控制器的信息,或使用新数据扩展复杂时间线。
  • $ _Session“复杂”登录和注销php($_Session “complication” on login and logout php)
    问题 我正在为大学做一个数据库项目,而我在这里遇到了一个问题。 我试图在没有会话时显示“登录”,而在有会话时显示“注销”。 但是实际上即使登录后,它仍然显示我“登录”,并且我尝试了print_r($ _ SESSION); 它告诉我变量未定义 我有一个注销文件: <?php session_start(); session_destroy(); header("Location:index.php"); ?> 和一个init.php文件: <?php session_start(); ?> 登录时会调用init.php。 这是index.php的一部分: <?php require 'db/connect.php'; require 'functions/security.php'; ?> <html> <head> <title>Home</title> <meta charset="UTF-8"> <link rel="stylesheet" href="css/common.css"> </head> <body> <div id="linking"> <?php //print_r($_SESSION); if (session_status() === PHP_SESSION_NONE) { ?> <a href="login.php">Log In</a> <?php
  • 使用 Swift 3 和后台任务更新复杂性(Updating complication with Swift 3 and background task)
    问题 对于watchOS 3,苹果建议更新与并发症WKRefreshBackgroundTask而不是使用getNextRequestedUpdateDate 。 如何使用新方法确定两次更新之间的时间? 我只会将我的数据请求(从 url)破解到getCurrentTimelineEntry并更新复杂性,但我认为这并不是 Apple 真正推荐的。 一个简短的代码示例将是一个很大的帮助。 回答1 我通常在不同的答案中对此进行了介绍,但我将在此处解决您的具体问题。 你是对的,你不应该破解复杂控制器来做任何(异步)获取。 数据源应该只负责按照复杂服务器的要求返回现有的数据。 这对于 watchOS 2 是正确的,在 watchOS 3 中仍然如此。 对于 watchOS 3,每次后台刷新都可以安排下一次。 流程概览: 在您的特定情况下,您可以等到WKURLSessionRefreshBackgroundTask任务完成下载。 此时,在完成现有后台任务之前安排下一次后台刷新。 届时,您的扩展程序将再次被唤醒以再次启动整个后台进程: 从您的网络服务请求新数据处理回复并更新您的数据存储告诉复杂程序自行更新(这将使用手头的新数据)。 更新码头快照安排即将到来的后台刷新任务将您当前的任务标记为已完成。 您甚至可以链接一系列不同的后台子任务,其中每个子任务处理刷新周期的一个单独方面
  • WCSession 尚未激活(WCSession has not been activated)
    问题 当我尝试发送某些内容时,出现 WCSession 未激活错误。 我不知道我做错了什么。 我已经测试了“必须”起作用的 serval 预制解决方案。 但它不适用于我的模拟器和物理设备。 一些代码: 我的应用程序委托: import UIKit import CoreData import WatchConnectivity @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate { var window: UIWindow? func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : String]) -> Void) { replyHandler(["message": "Hello Watch!"]) } func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { } func
  • 尝试在 watchOS 中进行后台刷新时不会调用 WKURLSessionRefreshBackgroundTask(WKURLSessionRefreshBackgroundTask isn't called when attempting to do background refreshes in watchOS)
    问题 我正在处理从 Web 服务获取预定数据的复杂功能。 每 20-30 分钟(或手动),我会安排一个 WKRefreshBackgroundTask 来执行此操作。 正如 Apple 所建议的,我希望操作系统通过后台NSURLSession处理这些数据的获取。 这是我用来下载我需要的数据的函数: func scheduleURLSession() { print("\nScheduling URL Session...") let backgroundSessionConfig:URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString) backgroundSessionConfig.sessionSendsLaunchEvents = true let backgroundSession = URLSession(configuration: backgroundSessionConfig) let downloadTask = backgroundSession.downloadTask(with: URL(string: "https://www.myserver.com/somedata")!) downloadTask.resume()
  • 那些年,我们一起踩过的3个spring事务的大坑
    前言 Spring框架已是JAVA项目的标配,其中Spring事务管理也是最常用的一个功能,但如果不了解其实现原理,使用姿势不对,一不小心就可能掉坑里。 为了更透彻的说明这些坑,本文分四部分展开阐述:第一部分简单介绍下Spring事务集成的几种方式;第二部分结合Spring源代码说明Spring事务的实现原理;第三部分通过实际测试代码介绍关于Spring事务的坑;第四部分是对本文的总结。 一、Spring事务管理的几种方式: Spring事务在具体使用方式上可分为两大类: 1. 声明式 基于 TransactionProxyFactoryBean的声明式事务管理 基于 和 命名空间的事务管理 基于 @Transactional 的声明式事务管理 2. 编程式 基于事务管理器API 的编程式事务管理 基于TransactionTemplate 的编程式事务管理 目前大部分项目使用的是声明式的后两种: 基于 和 命名空间的声明式事务管理可以充分利用切点表达式的强大支持,使得管理事务更加灵活。 基于 @Transactional 的方式需要实施事务管理的方法或者类上使用 @Transactional 指定事务规则即可实现事务管理,在Spring Boot中通常也建议使用这种注解方式来标记事务。 二、Spring事务实现机制 接下来我们详细看下Spring事务的源代码,进而了解其工作原理