Swift NSUserDefaults不适用于带Watch OS2的Xcode测试版

Swift NSUserDefaults不适用于带Watch OS2的Xcode测试版,swift,operating-system,nsuserdefaults,watchkit,watchos-2,Swift,Operating System,Nsuserdefaults,Watchkit,Watchos 2,我刚刚安装了最新的Xcode测试版,以尝试Swift 2,以及对Apple Watch开发部分所做的改进 事实上,我很难弄明白为什么在iOS和Watch OS2之间共享信息的基本NSUserDefaults方法不起作用 我随后检查了在这个过程中是否遗漏了什么,比如为手机应用程序和分机打开同一组,但我得到的结果是:什么都没有 以下是我在iPhone应用程序中为ViewController编写的内容: import UIKit class ViewController: UIViewControl

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

事实上,我很难弄明白为什么在iOSWatch OS2之间共享信息的基本
NSUserDefaults
方法不起作用

我随后检查了在这个过程中是否遗漏了什么,比如为手机应用程序和分机打开同一组,但我得到的结果是:什么都没有

以下是我在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 one利用了不同的组…他们没有共享信息,而是在本地存储信息


有人有同样的问题吗?知道如何修复吗?

使用watch OS2,您不能再使用共享组容器

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

NSUserDefaults(即使有应用程序组)在watchOS 2中的iPhone和手表之间不同步。如果您想从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) 确定何时需要将设置推送到手表
(此处未显示)

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];  
     }  
}  
- (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];  
}  
监视分机中
4) 接收用户信息传输

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

有一种复制旧功能的简单方法,我将旧组用户默认值导出到字典中,通过Watch Connectivity framework发送,然后将它们重新导入另一侧的用户默认值:

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

  • 添加WatchConnectivty框架
  • #导入
    并声明为
    wcsessionelegate
  • 添加代码以在应用程序启动后启动会话:

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

  • [[WCSession defaultSession]updateApplicationContext:[[NSUserDefaults alloc]initWithSuiteName:@“group.com.company.myapp”]dictionaryRepresentation]错误:无]

  • 接收设置并将其保存回默认设置-将其添加到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];
    }
    
    -(void)session:(WCSession*)session didReceiveApplicationContext:(NSDictionary*)applicationContext{
    NSLog(@“新会话上下文:%@”,applicationContext);
    NSUserDefaults*defaults=[[NSUserDefaults alloc]initWithSuiteName:@“group.com.company.myapp”];
    for(applicationContext.allKeys中的NSString*键){
    [默认设置setObject:[applicationContext objectForKey:key]forKey:key];
    }
    [默认同步];
    }
    

  • 小心维护对非WC设备的支持-使用
    if([WCSession isSupported])将updateApplicationContext调用包装起来。

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


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

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

    在iPhone应用程序中,按照以下步骤操作:

    选择要从中向Apple Watch推送数据的视图控制器,并在顶部添加框架

    import WatchConnectivity
    
    现在,与watch建立watch连接会话并发送一些数据

    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 {
    
    }
    
    现在,在您的手表应用程序中(此代码同样适用于浏览和其他手表套件应用程序类型)您添加了框架:

    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
            })
        }
    
    }
    
    就这些

    注意事项:

  • 您可以随时发送新的applicationContext,并且 不管手表是否在附近且已连接,或者手表是否 应用程序正在运行。这将在后台以 这是一种智能的方式,当 手表应用程序启动
  • 如果您的watch应用程序实际处于活动状态且正在运行,则应收到 在大多数情况下,邮件会立即发送
  • 您可以反转此代码,让手表向发送消息 iPhone应用程序也是如此
  • 查看手表应用程序时收到的应用程序上下文将只是您发送的最后一条消息。如果您在观看watch应用程序之前发送了20条消息,它将忽略前19条消息并处理第20条消息
  • 要在两个应用程序之间进行直接/硬连接,或进行后台文件传输或排队消息传递,请查看o

  • 请在问题中包含您的代码,这样断开的链接不会使这个问题对未来的读者毫无用处。.stringForKey(“共享”)已经返回了一个不需要强制转换的字符串。您应该使用nil coalescing操作符来展开它name_data=NSUSerDefaults()。stringForKey(“共享”)??