Подтвердить что ты не робот

NSUserDefaults не работает с бета-версией Xcode с Watch OS2

Я только что установил последнюю версию Xcode, чтобы попробовать Swift 2 и улучшения, внесенные в раздел разработки Apple Watch.

Мне действительно сложно понять, почему этот базовый метод NSUserDefaults для обмена информацией между iOS и Watch OS2 не работает.

Я последовал за этим пошаговым руководством, чтобы проверить, не пропустил ли я что-то в этом процессе, например, включив ту же группу для приложения телефона и расширения, но вот что я получил: НИЧЕГО.

Вот что я написал для ViewController в приложении iPhone:

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

И вот что я имею в InterfaceController для WatchKit:

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 Watch используют разные группы... они не используют информацию, они хранят их локально.

Есть ли у кого-то такая же проблема? Любая идея, как это исправить?

4b9b3361

Ответ 1

С часами OS2 вы больше не сможете использовать контейнеры общих групп. Apple Docs:

Наблюдайте за приложениями, совместно использующими данные с приложениями iOS с помощью общей группы контейнер должен быть переработан для обработки данных по-разному. В watchOS 2, каждый процесс должен управлять своей собственной копией любых общих данных в локальном контейнер. Для данных, которые фактически разделяются и обновляются оба приложения, для этого требуется использовать структуру Watch Connectivity для переместите эти данные между ними.

Ответ 2

NSUserDefaults (даже с группами приложений) не синхронизируют между iPhone и Watch в watchOS 2. Если вы хотите синхронизировать настройки с вашего 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) Сохраните полученные настройки для пользовательских настроек по умолчанию на часах

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

Ответ 3

Theres простой способ воспроизвести старую функциональность, я экспортирую старые значения по умолчанию для пользователей группы в словарь, отправлю их через структуру WatchConnectivity, а затем reimport в пользовательские настройки по умолчанию:

В приложениях "Телефон и чат":

  • Добавить структуру WatchConnectivty
  • #import <WatchConnectivity/WatchConnectivity.h> и объявите как WCSessionDelegate
  • Добавить код для запуска сеанса после запуска приложения:

    if ([WCSession isSupported]) {
            WCSession* session = [WCSession defaultSession];
            session.delegate = self;
            [session activateSession];
        }
    
  • Используйте это, чтобы отправить обновленные значения по умолчанию на другое устройство (вызов после текущего [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])

Ответ 4

Как уже упоминалось, общие NSUserDefaults больше не работают на WatchOS2.

Здесь быстрая версия @RichAble ответит еще несколькими заметками.

В приложении iPhone выполните следующие действия:

Выберите контроллер представления, который вы хотите перенести данные в Apple Watch, и добавьте фреймворк вверху.

import WatchConnectivity

Теперь создайте сеанс WatchConnectivity с часами и отправьте некоторые данные.

if WCSession.isSupported() { //makes sure it 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
        })
    }

}

Вот и все.

Примечания:

  • Вы можете отправить новый applicationContext так часто, как вам нравится, и он не имеет значения, находятся ли часы рядом и подключены или если часы приложение запущено. Это предоставляет данные в фоновом режиме в разумным способом и что данные сидят там, ожидая, когда приложение для просмотра.
  • Если ваше часовое приложение действительно активно и работает, оно должно получить сообщение немедленно в большинстве случаев.
  • Вы можете отменить этот код, чтобы отправлять сообщения отправки на iPhone аналогичным образом.
  • applicationContext, получаемый вашим приложением просмотра, когда он будет просмотрен, будет ТОЛЬКО последним отправленным вами сообщением. Если вы отправили 20 сообщений до просмотра приложения-наблюдателя, он будет игнорировать первые 19 и обработать 20-й.
  • Для прямого/жесткого соединения между двумя приложениями или для передачи файлов с фона или обмена сообщениями в очереди, просмотрите WWDC vide o.

Ответ 5

Мне потребовались часы и часы, чтобы получить это. Смотрите это очень полезное видео! Это дает вам основную идею о том, как использовать WatchConnectivity для совместного использования NSUserDefault между приложением iPhone и wacth!

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