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

【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中的项目进行配置。

【Swift 学习笔记】iCloud:Key-Value Storage_第1张图片
1.png

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

Step 2: 配置iCloud

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

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

【Swift 学习笔记】iCloud:Key-Value Storage_第2张图片
3.png

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

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

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

Step 3: demo 程序

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

【Swift 学习笔记】iCloud:Key-Value Storage_第5张图片
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 Storage)