SwiftiOS程序猿程序员

开始用Swift开发iOS 10 - 22 使用CloudKit

2017-08-03  本文已影响373人  Andy_Ron

上一篇 开始用Swift开发iOS 10 - 21 使用WKWebView和SFSafariViewController 学习打开网页,这一篇学习使用CloudKit。

iCloud最初乔布斯在WWDC2011是发布的,只为了给Apps、游戏能够在云端数据保存,让Mac和iOS之间数据自动同步所用。
最近几年才渐渐成长为云服务。如果想创建社交类型的,可以分享用户之间数据的app,就可考虑使用iCloud,这样就不需要自己再去构建一个后端APIs了。虽然可能由于国内的网络环境,iCloud实际应用效果并不好,不过还是有必要学一下的🙂。

如果开发了Web应用,同样也可以访问iOS应用的iCloud中数据。Apple分别提供了CloudKit JSCloudKit库。

CloudKit默认给我们的app提供一些免费的空间:

当app的用户的活跃数提高,免费空间也会随之提高,详细可查看官网介绍

理解CloudKit框架

CloudKit框架不仅提供了存储功能,还提供了开发者与iCloud之间的各种交互。ContainersdatabaseCloudKit框架的基础元素。

Containers and Database Record zones and Records

为应用添加CloudKit

在CloudKit Dashboard中管理 Record

使用 Convenience API获取public Database

CloudKit提供两种APIs让开发与iCloud交互:the convenience API 和 the operational API。

override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return restaurants.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for:
indexPath)
    // Configure the cell...
    let restaurant = restaurants[indexPath.row]
    cell.textLabel?.text = restaurant.object(forKey: "name") as? String
    if let image = restaurant.object(forKey: "image") {
        let imageAsset = image as! CKAsset
        if let imageData = try? Data.init(contentsOf: imageAsset.fileURL) {
            cell.imageView?.image = UIImage(data: imageData)
        } 
    }
    return cell
}

为什么慢?

测试以上代码,发现fetchRecordsFromCloud函数中的打印信息"Completed the download of Restaurant data"已经显示在控制台了,但是还需要过一段时间App中才能显示,也就是说向iCloud中获取完数据后才开始准备table view加载。

这边就需要使用到多线程的概念。在iOS中,UI更新(像table重新加载)必须在主线程执行。这样获取iCloud数据的线程在进行时,UI更新也在同步进行。

OperationQueue.main.addOperation {
    self.tableView.reloadData()
}

使用operational API获取public Database

** Convenience API**只适合简单和少量的查询。

加载指示(菊花转)

添加完发现** activity indicator view在控制器上面,这在Xcode中叫The Extra Views**

DiscoverTableViewController中添加接口,并关联。

  @IBOutlet var spinner: UIActivityIndicatorView!

viewDidLoad中添加代码:

  spinner.hidesWhenStopped = true
  spinner.center = view.center
  tableView.addSubview(spinner)
  spinner.startAnimating()

懒加载图片

懒加载图片就是先加载一个本地默认图片,暂时不加载远程图片,当图片准备好在去更新图片视图。

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        
        let restaurant = restaurants[indexPath.row]
        cell.textLabel?.text = restaurant.object(forKey: "name") as? String
        
        
        // Set the default image
        cell.imageView?.image = UIImage(named: "photoalbum")
        // Fetch Image from Cloud in background
        let publicDatabase = CKContainer.default().publicCloudDatabase
        let fetchRecordsImageOperation = CKFetchRecordsOperation(recordIDs:[restaurant.recordID])
        fetchRecordsImageOperation.desiredKeys = ["image"]
        fetchRecordsImageOperation.queuePriority = .veryHigh
        fetchRecordsImageOperation.perRecordCompletionBlock = { (record, recordID, error) -> Void in
            if let error = error {
                print("Failed to get restaurant image: \(error.localizedDescription)")
                return
            }
            if let restaurantRecord = record {
                OperationQueue.main.addOperation() {
                    if let image = restaurantRecord.object(forKey: "image") {
                        let imageAsset = image as! CKAsset
                        print(imageAsset.fileURL)
                        if let imageData = try? Data.init(contentsOf:
                            imageAsset.fileURL) {
                            cell.imageView?.image = UIImage(data: imageData)
                        }
                    }
                }
            }
        }
        publicDatabase.add(fetchRecordsImageOperation)
        return cell
    }

懒加载后发现,图片在其它视图显示后慢慢先后加载显示。

下拉刷新

UIRefreshControl提供了标准的下拉刷新特性。

        // Pull To Refresh Control
        refreshControl = UIRefreshControl()
        refreshControl?.backgroundColor = UIColor.white
        refreshControl?.tintColor = UIColor.gray
        refreshControl?.addTarget(self, action: #selector(fetchRecordsFromCloud), for: UIControlEvents.valueChanged)

每一次下拉是显示菊花转,并且调用fetchRecordsFromCloud方法。

if let refreshControl = self.refreshControl {
    if refreshControl.isRefreshing {
        refreshControl.endRefreshing()
    }
}
restaurants.removeAll()
tableView.reloadData()

使用CloudKit保存数据到iCloud

CKDatabasesave(_:completionHandler:)的方法可用来保存数据到iCloud。
实现用户新加数据时,既保存在本地的Core Data,有保存在iCloud中。

排序

CKQuery有属性sortDescriptors可用来排序。
DiscoverTableViewControllerfetchRecordsFromCloud方法,query定义后添加:

    query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

creationDate是默认的创建时间字段。

Exercise:修改Discover样式

    @IBOutlet var nameLabel: UILabel!
    @IBOutlet var locationLabel: UILabel!
    @IBOutlet var typeLabel: UILabel!
    @IBOutlet var thumbnailImageView: UIImageView!

代码

Beginning-iOS-Programming-with-Swift

说明

此文是学习appcode网站出的一本书 《Beginning iOS 10 Programming with Swift》 的一篇记录

系列文章目录

上一篇 下一篇

猜你喜欢

热点阅读