Apple Watch學習之路 資料儲存

wongstar發表於2017-12-14

App 的核心是內容.那內容都有哪些方式儲存呢?

我們知道在iOS中儲存資料一般會用以下四種方式:

  • NSKeyedArchiver:採用歸檔的形式來儲存資料,一般NSString、NSDictionary、NSArray、NSData、NSNumber等型別,可以直接用NSKeyedArchiver進行歸檔和恢復.
  • NSUserDefaults: 用來儲存配置資訊 特點是簡單方便.通過[NSUserDefaults standardUserDefaults]獲取例項來儲存簡單的資料。
  • 資料庫(Sqlite,Coredata)。儲存大量的資訊
  • 檔案儲存:各種檔案儲存。通過沙盒來進行儲存。

#####那Apple watch 端可以通過什麼方式來儲存呢?

WX20170901-093638@2x.png

  • plist NSUserDefaults是快速共享資訊的途徑。它適合儲存各種快速訪問和計算的小型資料,比如使用者名稱與檔案資訊。儲存在Watch Extension中.

需要注意的是實現資料共享時候 你需要設定App Group來讓裝置通過共享容器來實現資料共享,確保手錶擴充套件和ios target都已如此設定。基本上就是針對兩個裝置建立一個統一的App Group識別符號,如下圖所示:APP Groups 識別符號為group.com.db.iwatch

let defaults=NSUserDefaults(suiteName: "group.com.db.iwatch")

watch extension端和 ios phone端就可以實現資料共享啦

  • coredata watchos2 之後開始支援coredata啦。在watch 端怎麼實現coredata 儲存以及CRDU呢?

需要注意的是實現資料共享時候 APP Groups 識別符號為group.com.db.iwatch

要了解coredata,就必須理解下面四個類所代表的意思,下面分別介紹:

  • NSManagedObjectModel 代表了資料模型,也就是Xcode中建立的.xcdatamodel檔案中所表訴的資訊
  • NSPersistentStore 是資料存放的地方,可以是SQLite、XML(僅OS X)、二進位制檔案、或僅記憶體中
  • NSPersistentStoreCoordinator 是協調者,用來在NSManagedObjectContext和NSPersistentStore之間建立連線。
  • NSManagedObjectContext 是應用程式唯一需要訪問的類,其中提供了對資料操作的一系列介面。
  • NSManagedObject 是具體某個Table 對應的實體物件

通過上面簡單的描述來寫下面Watch端關於 首先初始化新建一個WatchCoreDataProxy.swift檔案,通過該類來運算元據庫。

public class WatchCoreDataProxy: NSObject {
   
   let sharedAppGroup:String = "group.com.db.iwatch"
   
//初始化單例該類
   public class var sharedInstance : WatchCoreDataProxy {
       struct Static {
           static let instance : WatchCoreDataProxy = WatchCoreDataProxy()
       }
       return Static.instance
   }
   
   // MARK: - Core Data stack
   
   public lazy var applicationDocumentsDirectory: URL = {
       // The directory the application uses to store the Core Data store file. This code uses a directory named "com.makeandbuild.ActivityBuilder" in the application's documents Application Support directory.
       
       
      let urls = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask )
       

       return urls[urls.count-1]
       }()
   //
   public lazy var managedObjectModel: NSManagedObjectModel = {
       
       
       
      // let proxyBundle = Bundle(identifier: "com.db.iwatch.WatchCoreDataProxy")
       
       
       //注意此處是Model名稱,xcdatamodel對應的位置
       let modelURL = Bundle.main.url(forResource: "Model", withExtension: "momd")
       
       //let proxyBundle = Bundle(identifier: "com.makeandbuild.WatchCoreDataProxy")
       
       // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
     
       
       //let modelURL =  proxyBundle?.url(forResource: "Model", withExtension: "momd")

       return NSManagedObjectModel(contentsOf: modelURL!)!
       }()
   
   public lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
       
      //注意這裡的shareAppGroup
       var sharedContainerURL: URL? = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: self.sharedAppGroup) as URL?
       
       if let sharedContainerURL = sharedContainerURL {
       
           let storeURL = sharedContainerURL.appendingPathComponent("Model.sqlite")
           
           print("the database mode url is:\(storeURL)")
           var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
           
       
           do {
               try coordinator!.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
           } catch {
               // Report any error we got.
               var dict = [String: AnyObject]()
               dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
               dict[NSLocalizedFailureReasonErrorKey] = "There was an error creating or loading the application's saved data." as AnyObject?
               
               dict[NSUnderlyingErrorKey] = error as NSError
               let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
               // Replace this with code to handle the error appropriately.
               // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
               NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
               abort()
           }
           
           return coordinator
       
       }
       return nil
       }()
   
   //mangedObjectContext範問資料庫的控制程式碼
   public lazy var managedObjectContext: NSManagedObjectContext? = {
       // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
       let coordinator = self.persistentStoreCoordinator
       if coordinator == nil {
           return nil
       }
       var managedObjectContext = NSManagedObjectContext()
       managedObjectContext.persistentStoreCoordinator = coordinator
       return managedObjectContext
       }()
   
   // MARK: - Core Data Saving support
   
 //儲存資料庫Context
   public func saveContext () {
       
        let context = self.managedObjectContext!
       
       if (context.hasChanges) {
           do {
               try
                   context.save()
           } catch {
               // Replace this implementation with code to handle the error appropriately.
               // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
               let nserror = error as NSError
               fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
           }
       }
   }

   
}
複製程式碼

下面在coredata資料庫中新增Songs Table

coredata@2x.png

然後通過Editor 按鈕 Create NSManagerObject SubClass 產生如下類

extension Songs {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Songs> {
        return NSFetchRequest<Songs>(entityName: "Songs");
    }

    @NSManaged public var albumId: String?
    @NSManaged public var coverUrl: String?
    @NSManaged public var createTime: String?
    @NSManaged public var duration: String?
    @NSManaged public var favorite: Int16
    @NSManaged public var name: String?
    @NSManaged public var songId: String?
    @NSManaged public var sourceUrl: String?
    @NSManaged public var artist: String?
    
}

複製程式碼

建立新增一條記錄到Song欄位中去

 public func createSong(songTmp:SongsModel){
        
        let song:Songs = NSEntityDescription.insertNewObject(forEntityName: SongManager.SONG_DATABASE, into: DataBaseManager.getContext()) as! Songs
        
        print("will insert songMode :\(songTmp)")
        
        song.albumId = songTmp.albumId
        song.name=songTmp.songName
        song.songId=songTmp.songId
        song.duration=songTmp.duration
        song.artist=songTmp.atrtisName
        song.coverUrl=songTmp.coverUrl
        song.favorite=Int16(songTmp.favorite!)!
   
        song.sourceUrl=songTmp.sourceUrl
        
    
        let time = Date().timeIntervalSince1970
        song.createTime = String.init(format: "%lld", time)
        print("the name is:\(song.name)")
        //對資料進行儲存.
        DataBaseManager.saveManagedContext()
        
        
    }
複製程式碼

查詢所有歌曲如下圖所示:

public func fetchAllSongs(sortKey:String = "createTime")->[Songs]{
        
        let fetchRequest = NSFetchRequest<Songs>(entityName: SongManager.SONG_DATABASE)
        
        
        let sortDescriptor = NSSortDescriptor(key: sortKey, ascending: true)
        
        fetchRequest.sortDescriptors=[sortDescriptor]
        var fetchedSongs:[Songs]=[]
        do {
           

                fetchedSongs = try DataBaseManager.getContext().fetch(fetchRequest)
            
        } catch{
            print("Failed to fetch employees: \(error)")
        }
        
        return fetchedSongs
        
        
    }
複製程式碼

###總結:

WatchOS可以通過coredata來儲存複雜的資料,plist來儲存較為簡單的資料,要實現app與watch 共享資料需要注意新增APP Groups 識別符號.

相關文章