23

我刚刚安装了最新的 Xcode 测试版来试用Swift 2以及对 Apple Watch 开发部分所做的改进。

我实际上很难弄清楚为什么这种在iOSWatch OS2NSUserDefaults之间共享信息的基本方法不起作用。

我按照这个分步教程检查我是否在此过程中遗漏了某些内容,例如为电话应用程序和分机打开同一个组,但这是我得到的:NOTHING

这是我在 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 中的内容:

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()
    }
}

我做了一些测试,似乎 iOS 应用程序和 Watch OS 使用了不同的组......他们没有共享信息,他们将它们存储在本地。

有人有同样的问题吗?知道如何解决吗?

4

5 回答 5

43

使用 watch OS2,您不能再使用共享组容器。 苹果文档:

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

于 2015-06-15T20:05:08.567 回答
18

NSUserDefaults(即使有应用程序组)不会在 watchOS 2 中的 iPhone 和 Watch 之间同步。如果你想从你的 iPhone 应用程序或 Settings-Watch.bundle 同步设置,你必须自己处理同步。

我发现在这种情况下,使用 WatchConnectivity 的用户信息传输非常有效。您将在下面找到如何实现此功能的示例。该代码仅处理从手机到手表的单向同步,但另一种方式的工作方式相同。

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)确定何时需要将设置推送到Watch
(此处未显示)

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) 将收到的设置保存到手表上的用户默认值

- (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];  
}  
于 2015-08-12T08:01:24.310 回答
12

有一种重现旧功能的简单方法,我将旧组用户默认值导出到字典中,将其发送到 WatchConnectivity 框架,然后将它们重新导入另一侧的用户默认值:

在电话和手表应用中:

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

    if ([WCSession isSupported]) {
            WCSession* session = [WCSession defaultSession];
            session.delegate = self;
            [session activateSession];
        }
    
  4. 使用它来将更新的默认值发送到另一台设备(在您的 current 之后调用[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 设备的支持 - 将 updateApplicationContext 调用与if ([WCSession isSupported])

于 2015-09-17T10:28:01.707 回答
7

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

这是@RichAble 答案的快速版本,还有一些注释。

在您的 iPhone App中,执行以下步骤:

选择要从中将数据推送到 Apple Watch 的视图控制器,然后在顶部添加框架。

import WatchConnectivity

现在,与手表建立 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 和其他手表工具包应用程序类型)您添加框架:

import WatchConnectivity

然后设置连接会话:

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. 要在 2 个应用程序之间进行直接/硬连接,或者进行后台文件传输或排队消息传递,请查看WWDC 视频o。
于 2016-01-26T19:47:53.287 回答
1

我花了好几个小时才得到这个。观看这个非常有用的视频!它为您提供了如何使用 WatchConnectivity 在 iPhone 应用程序和 wacth 之间共享 NSUserDefault 的基本概念!

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

于 2015-12-18T01:19:21.893 回答