ShawnXiaFei 2015-06-30
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并有清晰的接口。