NSUserDefaults无法在Watch OS2上使用Xcode beta

我刚刚安装了Xcode的最新testing版来尝试Swift 2 ,并对Apple Watch开发部分进行了改进。

我真的很难搞清楚为什么这个基本的NSUserDefaults方法来共享iOSWatch OS2之间的信息不工作。

我按照这个循序渐进的教程来检查是否在这个过程中丢失了一些东西,比如打开电话应用程序和扩展程序的同一个组,但这里是我得到的: 没有

以下是我在iPhone应用程序中为ViewController编写的内容:

 import UIKit class ViewController: UIViewController { @IBOutlet weak var lb_testo: UITextField! let shared_defaults:NSUserDefaults = NSUserDefaults(suiteName: "group.saracanducci.test")! var name_data:NSString? = "" override func viewDidLoad() { super.viewDidLoad() name_data = shared_defaults.stringForKey("shared") lb_testo.text = name_data as? String } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func upgrade_name(sender: AnyObject) { name_data = lb_testo.text shared_defaults.setObject(name_data, forKey: "shared") lb_testo.resignFirstResponder() shared_defaults.synchronize() } } 

以下是我在WatchKit的InterfaceController中所具有的function:

 import WatchKit import Foundation class InterfaceController: WKInterfaceController { @IBOutlet var lb_nome: WKInterfaceLabel! let shared_defaults:NSUserDefaults = NSUserDefaults(suiteName: "group.saracanducci.test")! var name_data:NSString? = "" override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) } override func willActivate() { super.willActivate() if (shared_defaults.stringForKey("shared") != ""){ name_data = shared_defaults.stringForKey("shared") lb_nome.setText(name_data as? String) }else{ lb_nome.setText("No Value") } } override func didDeactivate() { super.didDeactivate() } } 

我做了一些testing,似乎iOS应用程序和Watch OS利用不同的群体… 他们不共享信息 ,他们在本地存储他们。

有人有同样的问题? 任何想法如何解决它?

使用手表OS2,您不能再使用共享组容器。 Apple文档:

观察使用共享组容器与iOS应用程序共享数据的应用程序必须进行重新devise,以便以不同方式处理数据。 在watchOS 2中,每个进程必须pipe理本地容器目录中任何共享数据的副本。 对于两个应用程序实际共享和更新的数据,这需要使用Watch Connectivity框架在它们之间移动数据。

在watchOS 2中,NSUserDefaults(即使有应用程序组)也不会同步iPhone和手表。如果要同步来自iPhone应用程序或Settings-Watch.bundle的设置,则必须自己处理同步。

我发现在这种情况下使用WatchConnectivity的用户信息传输效果非常好。 下面你会find一个你如何实现这个的例子。 该代码只处理从手机到手表的单向同步,但另一种方式的工作原理是一样的。

iPhone应用程序中
1)准备需要同步的设置字典

 - (NSDictionary *)exportedSettingsForWatchApp { NSUserDefaults *userDefaults = [self userDefaults]; // the user defaults to sync NSSet *keys = [self userDefaultKeysForWatchApp]; // set of keys that need to be synced NSMutableDictionary *exportedSettings = [[NSMutableDictionary alloc] initWithCapacity:keys.count]; for (NSString *key in keys) { id object = [userDefaults objectForKey:key]; if (object != nil) { [exportedSettings setObject:object forKey:key]; } } return [exportedSettings copy]; } 

2)确定何时需要将设置推送到手表
(这里没有显示)

3)将设置推送到手表

 - (void)pushSettingsToWatchApp { // Cancel current transfer [self.outstandingSettingsTransfer cancel]; self.outstandingSettingsTransfer = nil; // Cancel outstanding transfers that might have been started before the app was launched for (WCSessionUserInfoTransfer *userInfoTransfer in self.session.outstandingUserInfoTransfers) { BOOL isSettingsTransfer = ([userInfoTransfer.userInfo objectForKey:@"settings"] != nil); if (isSettingsTransfer) { [userInfoTransfer cancel]; } } // Mark the Watch as requiring an update self.watchAppHasSettings = NO; // Only start a transfer when the watch app is installed if (self.session.isWatchAppInstalled) { NSDictionary *exportedSettings = [self exportedSettingsForWatchApp]; if (exportedSettings == nil) { exportedSettings = @{ }; } NSDictionary *userInfo = @{ @"settings": exportedSettings }; self.outstandingSettingsTransfer = [self.session transferUserInfo:userInfo]; } } 

手表扩展中
4)接收用户信息传输

 - (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *, id> *)userInfo { NSDictionary *settings = [userInfo objectForKey:@"settings"]; if (settings != nil) { // Import the settings [self importSettingsFromCompanionApp:settings]; } } 

5)将收到的设置保存到Watch上的用户默认值

 - (void)importSettingsFromCompanionApp:(NSDictionary *)settings { NSUserDefaults *userDefaults = [self userDefaults]; // the user defaults to sync NSSet *keys = [self userDefaultKeysForWatchApp]; // set of keys that need to be synced for (NSString *key in keys) { id object = [settings objectForKey:key]; if (object != nil) { [userDefaults setObject:object forKey:key]; } else { [userDefaults removeObjectForKey:key]; } } [userDefaults synchronize]; } 

这是一个简单的方法来重现旧的function,我将旧的组用户默认值导出到一个字典,通过WatchConnectivity框架发送,然后重新导入到另一侧的用户默认值:

在手机和手表应用程序中:

  1. 添加WatchConnectivty框架
  2. #import <WatchConnectivity/WatchConnectivity.h>并声明为WCSessionDelegate
  3. 添加代码以在应用启动后启动会话:

     if ([WCSession isSupported]) { WCSession* session = [WCSession defaultSession]; session.delegate = self; [session activateSession]; } 
  4. 使用此function将更新后的默认值发送到其他设备(在当前[defaults synchronize]之后调用):

[[WCSession defaultSession] updateApplicationContext:[[[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.myapp"] dictionaryRepresentation] error:nil];

  1. 接收并保存设置返回到默认值 – 将此添加到WCDelegate:

     -(void)session:(WCSession *)session didReceiveApplicationContext:(NSDictionary<NSString *,id> *)applicationContext { NSLog(@"New Session Context: %@", applicationContext); NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.myapp"]; for (NSString *key in applicationContext.allKeys) { [defaults setObject:[applicationContext objectForKey:key] forKey:key]; } [defaults synchronize]; } 

小心保持对非WC设备的支持 – 用if ([WCSession isSupported])包装updateApplicationContext调用

如前所述,共享NSUserDefaults不再适用于WatchOS2。

这里有@ RichAble的答案的快速版本,还有一些笔记。

在你的iPhone App中 ,按照下列步骤操作:

select您想要将数据推送到Apple Watch的视图控制器,然后在顶部添加框架。

 import WatchConnectivity 

现在,与手表build立WatchConnectivity会话并发送一些数据。

 if WCSession.isSupported() { //makes sure it's not an iPad or iPod let watchSession = WCSession.defaultSession() watchSession.delegate = self watchSession.activateSession() if watchSession.paired && watchSession.watchAppInstalled { do { try watchSession.updateApplicationContext(["foo": "bar"]) } catch let error as NSError { print(error.description) } } } 

请注意,如果你跳过设置委托,这将不起作用,所以即使你从不使用它,你必须设置它并添加这个扩展:

 extension MyViewController: WCSessionDelegate { } 

现在,在你的手表应用程序 (这个确切的代码适用于Glances和其他手表套件应用程序types以及),你添加框架:

 import WatchConnectivity 

然后你build立连接会话:

 override func awakeWithContext(context: AnyObject?) { super.awakeWithContext(context) let watchSession = WCSession.defaultSession() watchSession.delegate = self watchSession.activateSession() } 

你只需要听取和处理来自iOS应用程序的消息:

 extension InterfaceController: WCSessionDelegate { func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) { print("\(applicationContext)") dispatch_async(dispatch_get_main_queue(), { //update UI here }) } } 

这就是它的全部。

注意事项:

  1. 您可以随时发送新的applicationContext,无论手表是在附近或连接,还是手表应用程序正在运行。 这将以智能的方式在后台传输数据,并且在手表应用程序启动时,数据就在那里等待。
  2. 如果您的手表应用程序确实处于活动状态并正在运行,则应在大多数情况下立即收到该信息
  3. 您可以反转此代码,让手表以相同的方式将消息发送到iPhone应用程序。
  4. 您的手表应用程序在查看时收到的applicationContext将只是您发送的最后一条消息。 如果您在查看手表应用程序之前发送了20条消息,则会忽略前19条并处理第20条消息。
  5. 要在两个应用程序之间进行直接/硬连接,或者进行后台文件传输或排队消息,请查看WWDCvideo 。

花了我几个小时才能得到这个。 观看这个非常有用的video! 它提供了如何使用WatchConnectivity在iPhone应用程序和wacth之间共享NSUserDefault的基本思路!

https://www.youtube.com/watch?v=VblFPEomUtQ