美文网首页ios 开发Swift学习笔记代码改变世界
【Swift 学习笔记】iCloud:Key-Value Sto

【Swift 学习笔记】iCloud:Key-Value Sto

作者: L萧越 | 来源:发表于2015-01-08 10:35 被阅读1811次

    【Swift 学习笔记】iCloud:Key-Value Storage

    想让自己的程序支持iCloud。搜索发现OC的教程比较多。照猫画虎,翻译+整理一个swift版本的。
    参考:http://code.tutsplus.com/tutorials/working-with-icloud-key-value-storage--pre-37542

    开始之前

    需要一个付费的iOS 开发者账号。
    至少要2台iOS设备才可以测试数据同步功能。(iOS Simulator无法做iCloud Storage的测试)

    如果你手头没有iOS开发者账号,或者没有2台iOS设备。这篇文章还是可以让你了解如何配置iCloud的,如何使用iCloud让你的程序变得更好。

    Step 1:新建一个项目

    首先需要对本地Xcode中的项目进行配置。

    1.png

    用创建一个新的项目。
    template: Single View Application project
    name: iCloudKeyValue
    Language: Swift

    Step 2: 配置iCloud

    在Xcode 6中,配置iCloud比较简单。

    在Project Navigator 中选择项目。在Capabilities中将iCloud的switch开关设置为On。

    3.png

    Xcode会自动帮你 创建App ID,将Entitlements权限文件添加到项目中

    5.png
    • 进入开发者中心
    • 点击右上角的“Certificates, Identifiers & Profiles”
    • 在新的页面中,选择“Provisioning Profiles”
    • 在新页面中选择App IDs。可以看到,通过刚才的步骤a,Xcode已经自动创建了App ID: brincell.iCloudKeyValue
    • 点击这个App ID,展开。你会发现iCloud 服务处于Configurable状态。
    appIDConfiguarbel.png

    (以Key-Value Storage来使用iCloud,不需要iCloud Container文件。所以这里是需要配置的状态。)

    Step 3: demo 程序

    demo 用的是Apple官方教程YourFirstApp
    稍加修改,改为iOS App。

    Screen Shot 2015-01-07 at 11.33.32 AM.png
    class Track: NSObject {
      var volume : Float = 0
    }
    
    class ViewController: UIViewController {
      let track = Track()
     
     
      @IBOutlet weak var textField: UITextField!
      @IBOutlet weak var slider: UISlider!
     
      @IBAction func mute(sender: AnyObject) {
        track.volume = 0.0
        updateUserInterface()
        println("click mute button")
      }
    
      @IBAction func textField(sender: AnyObject) {
        var newValue = slider.value
        track.volume = newValue
        updateUserInterface()
        println("\(slider.value)")
      }
    
      func updateUserInterface() {
        var volume = track.volume
        self.textField.text = "\(volume)"
        self.slider.value = volume
      }
    }
    

    运行程序。测试slider和Mute按钮能否正常工作。拖动slider,textField显示对应的值。

    Step 4. 保存数据和加载数据

    现在在手机上退出重启程序,数据是无法保存的。
    我们这里用user defaults database 来保存数据。

    添加saveVolume() loadVolume() 两个方法。

    func saveVolume() {
        let ud = NSUserDefaults.standardUserDefaults()
        let trackVolume = track.volume
        ud.setValue(trackVolume, forKey: "Track")
    }
    
    func loadVolume(){
        let ud = NSUserDefaults.standardUserDefaults()
        if ud.valueForKey("Track") != nil {
            track.volume = ud.valueForKey("Track") as Float
        } else {
            track.volume = 5
        }
    }
    

    在viewDidLoad() 中调用loadVolume()。在Mute和Slider的action中调用saveVolume()方法。

    class ViewController: UIViewController {
      let track = Track()
     
     
      @IBOutlet weak var textField: UITextField!
      @IBOutlet weak var slider: UISlider!
     
      @IBAction func mute(sender: AnyObject) {
        track.volume = 0.0
        updateUserInterface()
        saveVolume()
        println("click mute button")
      }
    
      @IBAction func textField(sender: AnyObject) {
        var newValue = slider.value
        track.volume = newValue
        updateUserInterface()
        saveVolume()
        println("\(slider.value)")
      }
    
      func updateUserInterface() {
        var volume = track.volume
        self.textField.text = "\(volume)"
        self.slider.value = volume
      }
     
      override func viewDidLoad() {
        super.viewDidLoad()
        loadVolume()
        updateUserInterface()
    
      }
       
        func saveVolume() {
            let ud = NSUserDefaults.standardUserDefaults()
            let trackVolume = track.volume
            ud.setValue(trackVolume, forKey: "Track")      
        }
    
        func loadVolume(){
            let ud = NSUserDefaults.standardUserDefaults()
            if ud.valueForKey("Track") != nil {
                track.volume = ud.valueForKey("Track") as Float
            } else {
                track.volume = 5
            }
        }
    }
    

    运行程序。双击Home,在程序列表中上划完全退出demo。重新启动demo看是否能够成功保存数据。

    Step 5. iCloud 同步数据

    为了让demo程序更加好用,我们用iCloud来同步设备间的数据。这个过程非常的简单。
    iCloud's Key-Value Storage 和 NSUserDefaults 用法非常的像,也是存储key-value键值对。iCloud对应的类叫做 NSUbiquitousKeyValueStore。

    我们先来实现iCloud的存储。
    在saveVolume() 方法中,仿造NSUserDefaults写NSUbiquitousKeyValueStore方法。(注:NSUserDefaults可以用setValue方法来存储。NSUbiquitousKeyValueStore用这个方法程序缺一直crash。不知道是swift的坑还是什么。这里先转换成double值,用setDouble试一下。)

    func saveVolume() {
        let ud = NSUserDefaults.standardUserDefaults()
        let trackVolume = track.volume
        ud.setValue(trackVolume, forKey: "Track")
       
        // Save to iCloud
        let store = NSUbiquitousKeyValueStore.defaultStore()
        let trackVolumeDouble = Double(trackVolume)
        store.setDouble(trackVolumeDouble, forKey: "Track")
        store.synchronize()
        println("Saving to iCloud")
       
    }
    

    那么我们的demo程序是如何知道其他设备中的程序已经改变了iCloud 中的Key-Value,把改动同步到当前设备的呢?
    每当 Key-Value 被改变,程序会发送一个notification出来,我们的程序收到这个notification,把数据覆盖到本地就可以了。

    在 viewDidLoad() 中做4件事。

    1. 首先得到Key-Value Store的引用。

    2. 把我们的View Controller当做一个监听器。监听NSUbiquitousKeyValueStoreDidChangeExternallyNotification
      当接受到这个notification的时候,用updateKeyValuePairs: 方法来处理它。

    3. 给store发送一个synchronize消息。

    4. 刷新数据

       override func viewDidLoad() {
       super.viewDidLoad()
      
       let store = NSUbiquitousKeyValueStore.defaultStore()
       NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("updateKeyValuePairs:"), name: NSUbiquitousKeyValueStoreDidChangeExternallyNotification, object: store)
       store.synchronize()
       loadVolume()
       updateUserInterface()
      
      }
      
      func updateKeyValuePairs(notification: NSNotification) {
       println("updateKeyValuePairs")
       let userInfo = notification.userInfo
       let changeReason: AnyObject? = userInfo?["NSUbiquitousKeyValueStoreChangeReasonKey"]
       var reason = -1
      

      if (changeReason == nil) {
      return
      } else {
      reason = changeReason as Int
      println("reason is: (reason)")
      }

       if (reason == NSUbiquitousKeyValueStoreServerChange) || (reason == NSUbiquitousKeyValueStoreInitialSyncChange) {
         let changeKeys = userInfo?["NSUbiquitousKeyValueStoreChangedKeysKey"] as NSArray
         let store = NSUbiquitousKeyValueStore.defaultStore()
        
         for key in changeKeys {
           if key.isEqualToString("Track") {
             // Update Data Source
             let trackVolumeFromStore = store.doubleForKey("Track") as Double
             println("track volume from store: \(trackVolumeFromStore)")
             // Save Local Copy
             track.volume = Float(trackVolumeFromStore)
             let ud = NSUserDefaults.standardUserDefaults()
             ud.setValue(trackVolumeFromStore, forKey: "Track")
            
             updateUserInterface()
           }
         }
       }
      

      }

    在两台设备中运行程序。改变一台设备的数据。观察另一台设备的打印日志。可以看到它接受到通知,调用了
    updateKeyValuePairs:

    GitHub:

    https://github.com/vivijie/iCloudTest

    参考文献:

    http://code.tutsplus.com/tutorials/working-with-icloud-key-value-storage--pre-37542

    https://developer.apple.com/library/ios/documentation/General/Conceptual/iCloudDesignGuide/Chapters/Introduction.html#//apple_ref/doc/uid/TP40012094

    相关文章

      网友评论

      本文标题:【Swift 学习笔记】iCloud:Key-Value Sto

      本文链接:https://www.haomeiwen.com/subject/gfmxxttx.html