NSUserDefaults没有使用Watch OS2开发Xcode beta

时间:2015-06-15 17:50:24

标签: swift operating-system nsuserdefaults watchkit watch-os-2

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

我实际上很难弄清楚为什么在 iOS 观看OS2 之间分享信息的基本NSUserDefaults方法不是'工作。

我跟着this step-by-step tutorial检查我是否错过了过程中的某些内容,比如为手机应用程序和扩展程序启用了相同的组,但这是我得到的内容: 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可以利用不同的群体...... 他们不共享信息,他们将它们存储在本地。

有人有同样的问题吗?知道怎么解决吗?

5 个答案:

答案 0 :(得分:41)

使用手表OS2,您无法再使用共享组容器。 Apple Docs:

  

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

答案 1 :(得分:18)

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

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

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)将设置按下至Watch

- (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];  
}  

答案 2 :(得分:12)

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

在手机和观看应用中:

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

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

  5. [[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];
      }
      
    2. 小心保持对非WC设备的支持 - 使用if ([WCSession isSupported])

      包装您的updateApplicationContext调用

答案 3 :(得分:7)

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

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

在您的iPhone应用中,请按以下步骤操作:

选择要将数据推送到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 vide o。

答案 4 :(得分:1)

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

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