虽然苹果大肆宣传iCloud和CoreData的完美合作,但是在iOS7之前,试图用iCloud同步CoreData数据简直就是一场噩梦,而且苹果自己也承认了之前的很多bug和不稳定,这让Apple又要站出来说他们的工程师修复了iOS7的bug,增强了体验,balabala,关键是对于程序员来说,将iCloud集成到CoreData中变得异常简单。在Apple的官方文档中,配置工作已经描述的非常清楚了。简单来说,可以概括为三步:在iTunesConnect中创建一个AppID,在Xcode中找到项目的Capabilities选项卡并开启iCloud选项。这将为您创建一个默认的iCloud容器。名称格式为“com.XXX.yourAppID”。添加NSPersistentStore时,将持久存储名称传递给选项参数。自己创造一个吧。Thesamplecodeisasfollows:NSDictionary*storeOptions=@{NSPersistentStoreUbiquitousContentNameKey:@"MyAppCloudStore"};NSPersistentStore*store=[coordinatoraddPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURLoptions:storeOptionserror:&error];对NSPersistentStoreCoordinatorStoresWillChangeNotification,NSPersistentStoreCoordinatorStoresDidChangeNotification和NSPersistentStoreDidImportUbiquitousContentChangesNotification这三个通知进行注册以方便接收消息后对数据进行处理。***使用NSNotificationCenter的addObserverForName:object:queue:usingBlock:方法,逻辑更清晰,代码更紧凑。***贴上Swift现实persistentStoreCoordinator的代码:varpersistentStoreCoordinator:NSPersistentStoreCoordinator!{if_persistentStoreCoordinator==nil{letstoreURL=self.applicationDocumentsDirectory.URLByAppendingPathComponent("HardChoice.sqlite")varerror:NSModel?=nil_persistentStoreCoordinator=:NSPersistentStoreCoordinator(managedStoreCoordinator)//iCloudnotificationsubscriptionsletdc=NSNotificationCenter.defaultCenter()dc.addObserverForName(NSPersistentStoreCoordinatorStoresWillChangeNotification,object:self.persistentStoreCoordinator,queue:NSOperationQueue.mainQueue(),usingBlock:{(note)->Voidinself.managedObjectContext.performBlock({()->Voidinvarerror:NSError?=nilifself.managedObjectContext.hasChanges{if!self.managedObjectContext.save(&error){println(error?.description)}}self.managedObjectContext.reset()})})dc.addObserverForName(NSPersistentStoreCoordinatorStoresDidChangeNotification,object:self.持久存储坐标r,队列:NSOperationQueue.mainQueue(),usingBlock:{(note)->Voidinself.managedObjectContext.performBlock({()->Voidinvarerror:NSError?=nilifself.managedObjectContext.hasChanges{if!self.managedObjectContext.save(&error){println(error?.description)}}})})dc.addObserverForName(NSPersistentStoreDidImportUbiquitousContentChangesNotification,object:self.persistentStoreCoordinator,queue:NSOperationQueue.mainQueue(),usingBlock:{(note)->Voidinself.managedObjectContext.performBlock({()->Voidinself.managedObjectContext.mergeChangesFromContextDidSaveNotification(注)})})if_persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType,configuration:nil,URL:storeURL,options:[NSPersistentStoreUbiquitousContentNameKey:"MyAppCloudStore"],error:&error)==nil{println("Unresolvederror\(error),\(error?.userInfo)")abort()}}return_persistentStoreCoordinator!}var_persistentStoreCoordinator:NSPersistentStoreCoordinator?=nil当然也可以使用lazy关键字实现persistentStoreCoordinator属性的延迟加载。有人抽象出了CoreData与iCloud集成的整个逻辑,比如iCloudCoreDataStack。没有必要使用声称可以更轻松地匹配CoreData和iCloud的第三方库,因为Apple在iOS7中确实已经做到了极其简单。然而,当Xcode6和iOS8来袭的时候,坑一个接一个地出现。首先是iCloudDrive,它和之前的iCloud有冲突。如果要升级,请彻底升级,让所有测试机升级iCloudDrive。然后在Xcode6中打开Capabilities选项卡的iCloud选项卡后,下面的场景简直就是低谷:怎么选,怎么选?!只能说按照上图选择是对的。顺便说一句,iCloud默认容器名称格式已更改为“iCloud.com.yourname.yourAppID”。其实,这是不准确的。正式名称是“iCloud.$(CFBundleIdentifier)”,后面的美元符号所指代的变量是General中Identity栏中的“BundleIdentifier”值。另外,“Key-valuestorage”和“CloudKit”选项可以不选,但是“iCloudDocuments”必须勾选,否则无法同步CoreData数据。PS:CloudKit是苹果新推出的基于iCloud的云数据存储服务,提供低成本的云存储,可以通过用户的iCloud账户共享应用数据作为后台服务。接下来,是时候检查我们是否已成功添加iCloud容器。可以尝试在applicationDidFinishLaunchingWithOptions方法中获取容器的URL来判断:letcontainerURL=NSFileManager.defaultManager().URLForUbiquityContainerIdentifier("iCloud.com.yulingtianxia.HardChoice")ifcontainerURL!=nil{println("success:\(containerURL)")}else{println("URL=nil")}如果iCloud中的Capabilities选项卡中没有勾选“iCloudDocuments”,则“URLForUbiquityContainerIdentifier”方法将始终返回nil。看一下苹果开发者论坛上关于这个话题的讨论PS:官方文档不建议在主线程使用URLForUbiquityContainerIdentifier方法,因为返回URL可能需要很长时间,阻塞主线程。这仅供测试使用。不过要判断iCloud是否真的配合CoreData正常工作,苹果官方文档写的很详细:UsingtheiCloudDebuggingTools当我兴冲冲的打开Xcode中的debugnavigator,点击左边的iCloud查看状态时,我被这一切惊呆了在我前面。卡住:“iCloudUsage”告诉我状态不可用,但是右下角的日志显示Usinglocalstorage从1变成了0,证明我的APP(HardChoice)已经从CoreData使用localpersistent转过来了存储到使用“支持iCloud的”持久存储库。“传输活动”中的直方图显示数据已从iCloud下载。而这其实应该是Xcode6的一个bug,苹果开发者论坛已经有人讨论过了。根据我的测试,在只勾选“Key-valuestorage”或者在模拟器上调试的时候不会出现“iCloudUsage”。而且即使出现“iCloudUsage”,状态也一直是Disabled,“TransferActivity”也不是很敏感。我唯一能信任的就是CoreData的日志。但是我们可以看一下“我的Mac”的“iCloudUsage”而不是iPhone的“iCloudUsage”:在“Documents”一栏可以看到我已经同步了两台设备的数据,而“mobile”后面是我的设备号。展开数据可以看到更详细的同步记录:虽然可以通过“我的Mac”看到iCloud和CoreData之间的数据同步记录,但是“文档”在Xcode6.1.1中的显示不是很正常。在最新的Xcode6.虽然在2beta版本中修复了“文档”的显示问题,但“iCloudUsage”的各种BUG依然存在。***,确保网络正常。我在中软培训一个月的时候,网络极差,或者iCloud被封,一直没能调试成功。贴一张HardChoice同步成功的测试图,因为我这个demo是用Swift写的,所以喜欢用Swift的可以直接贴我的部分源码使用:
