iOS App与WatchKit Extension的数据通信

ShawnXiaFei 2015-06-30

iOS App与WatchKit Extension的数据通信

NSUserDefaults

NSUserDefaults是快速共享信息的途径。它适合存储各种快速访问和计算的小型数据,比如用户名与档案信息。如果希望使用UserDefaults,请用于静态数据这样用户不必考虑数值的变化。

你需要设定App Group来让设备通过共享容器来实现数据共享,确保手表扩展和ios target都已如此设置。基本上就是针对两个设备创建一个统一的App Group标识符。如果需要删除它,可以以类似的方法进行。

你可以通过之前创建的App Group名来使用defaults,基本上就是为特定的key键值设置对象。在iPhone上,用户输入了文本,保存,文本就存到了应用共享的UserDefaults里。在Watch上,你可以从AppGroup得到defaults然后进行手表显示内容的更新。

// on the iPhone app 


letdefaults=NSUserDefaults(suiteName:"group.com.natashatherobot.userdefaults") 


letkey="userInput" 


 


overridefuncviewDidLoad(){ 


super.viewDidLoad() 


textLabel.text=defaults?.stringForKey(key)??"Type Something..." 


} 


@IBActionfunconSaveTap(sender:AnyObject){ 


 


letsharedText=textField.text 


 


textLabel.text=sharedText 


 


defaults?.setObject(sharedText,forKey:key) 


defaults?.synchronize() 


} 


// WatchKit 


classInterfaceController:WKInterfaceController{ 


@IBOutletweakvartextLabel:WKInterfaceLabel! 


 


letdefaults=NSUserDefaults(suiteName: 


"group.com.natashatherobot.userdefaults") 


 


varuserInput:String?{ 


defaults?.synchronize() 


returndefaults?.stringForKey("userInput") 


} 

NSFileCoordinator

对更大型的数据来说,NSFileCoordinator是管理应用和watch扩展的共享空间里文件的方式之一。对于有限列表的内容它很合适,同时也适用于图像文件。

下面的例子是个简单的代办事项列表app,在手机上增加任务然后暑假传输到WatchKit扩展并在手表上显示。你的视图控制器需要遵循NSFilePresenter协议,除了实现两个必需方法,其它不是很关键。FilePresenter协议有一个item URL,就是填你的AppGroup标识符的地方。通过URL,你在对应目录建立一个文件。有必要的话你也可以通过操作队列来控制多线程访问。

另外,presentedItemDidChange这个代理方法,在FilePresenter里通知你是否一个对象发生了改变,来让你更新app数据而无需用户手动刷新。

然而这里还是有个关于NSFileCoordinator与NSFilePresenter 的bug而不方便在扩展里使用。具体可参见Natasha的网站。

在代办事项数组里利用FileCoordinator写入一个文件,可以通过读写文件以实现打包和解包事项的数据到事项数组,接下来可以依据文件里的事项数据计算生成表格。需要注意的是如果你设计了删除功能,而watch扩展和iPhone应用都能修改文件,会遇到线程同步的麻烦。

// iPhone app 


privatefuncsaveTodoItem(todoItem:String){ 


 


// write item into the todo items array 


ifletpresentedItemURL=presentedItemURL{ 


 


fileCoordinator.coordinateWritingItemAtURL(presentedItemURL,options:nil,error:nil) 


{[unownedself](newURL)->Voidin 


 


self.todoItems.insert(todoItem,atIndex:0) 


 


letdataToSave=NSKeyedArchiver.archivedDataWithRootObject(self.todoItems) 


letsuccess=dataToSave.writeToURL(newURL,atomically:true) 


} 


} 


} 


// in the Watch 


// MARK: Populate Table From File Coordinator 


 


privatefuncfetchTodoItems(){ 


 


letfileCoordinator=NSFileCoordinator() 


 


ifletpresentedItemURL=presentedItemURL{ 


 


fileCoordinator.coordinateReadingItemAtURL(presentedItemURL,options:nil,error:nil) 


{[unownedself](newURL)->Voidin 


 


ifletsavedData=NSData(contentsOfURL:newURL){ 


self.todoItems=NSKeyedUnarchiver.unarchiveObjectWithData(savedData)as[String] 


self.populateTableWithTodoItems(self.todoItems) 


} 


} 


} 


} 

Frameworks

“If the code appears more than once, it probably belongs in a framework.(如果代码出现超过一次,应该考虑能否放到框架里)”

-WWDC 2014, Building Modern Frameworks

框架对于业务逻辑、CoreData、可重用UI组件来说很棒。就像WWDC里说的那样,你可以将重复代码放到框架里。在FileCoordinator的例子里,我们获取和读写文件的代码出现了两次,可以把它们提取到一个framework框架里。建立框架很简单:建立新target,选择Cocoa Touch framework,然后命名。它会在你的iOS应用里自动链接,因此也不要忘了在WatchKit扩展里进行链接。

关键的一点,特别是对于Swift语言来说,应该把框架认作一个API。它需要声明为公共的(public),因为这是iOS应用和watchkit扩展共用的接口。因此如果你在建立对象类,确保public关键字也加上了。这样在手机和手表应用里你导入了框架就可以访问任何公共内容。

importWatchKit 


importMySharedDataLayer 


classInterfaceController:WKInterfaceController{ 


@IBOutletweakvarfavoriteThingsLabel:WKInterfaceLabel! 


 


overridefuncawakeWithContext(context:AnyObject?){ 


super.awakeWithContext(context) 


 


letmyFavoriteThings=MySharedData().myFavoriteThings 


 


letfavoriteThingsString=", ".join(myFavoriteThings) 


favoriteThingsLabel.setText("My favorite things are \(favoriteThingsString)") 


} 


} 

Keychain Sharing

钥匙链共享是针对更高安全性要求的数据的。UserDefaults提供的安全性不满足时,你可以用钥匙链共享来保障信息安全及跨扩展的共享能力。

WatchKit目前的一个大问题是没有认证机制。苹果提供了KeychainIteamWrapper的示例,但API太老不支持ARC。我推荐使用这个版本https://gist.github.com/dhoerl/1170641,它基于ARC并有清晰的接口。

相关推荐