作者:坐隐在线

iOS中实现SQLite数据库云存储(iCloud)大概需要三步:
一、设置项目支持iCloud
二、persistentStoreCoordinat or中设置对iCloud存取
三、设置iCloud数据变化时的一个通知监听,以便在数据变化时同步本地用户界面。

下面进行看图说话:
1,新建一个Master-Detail iOS项目。

ios开发云存储 apple云存储_SQL

2,设置项目名称为TestiCloud,勾选Use Core Data,项目将自动创建一个SQLite数据库,便于测试。然后一路下一步完成项目创建。

ios开发云存储 apple云存储_云存储_02


3,登录苹果的开发者中心:developer.apple.com,点击iOS Provisioning Portal,使项目支持iCloud

ios开发云存储 apple云存储_sqlite_03


4,建立一个新的App ID,如果是使原有项目支持iCloud,则跳过第4、5步。

ios开发云存储 apple云存储_SQL_04


5,填写描述及Bundle ID,这里是TestiCloud和net.zuoyin.TestiCloud

ios开发云存储 apple云存储_sqlite_05


6,创建成功后列表中将出现新建的App ID(如果是原来的项目则在此直接修改),点击configure

ios开发云存储 apple云存储_sqlite_06



7、勾选Enable for iCloud,弹出一个对话框,提示项目需重建provisioning,点击OK

ios开发云存储 apple云存储_SQL_07


8,点击左栏的Provisioning,然后点New Profile(如果是老项目,删掉原来的provisioning,重建)

ios开发云存储 apple云存储_SQL_08


9,建立provisioning,注意App ID的选择

ios开发云存储 apple云存储_ios开发云存储_09


10,下载新建的provisioning,拖到Organizer中,然后打开新建项目的Code signing,设置为相应的provisioning.

ios开发云存储 apple云存储_ios开发云存储_10



11,打开targets的Summary设置面板,向下拉,找到Entitlements,勾选Entitlements File(你会发现勾选后项目导航栏会增加一个名为TestiCloud.entitlements的文件),然后勾选Enable iCloud,key-Value Store程序中没用,所以不管这个(这是另外两种使用iCloud的方式中的一种,Key-Value Store类似于 NSUserDefaults的保存键值对,另一种是使用NSDocument管理文档,使用方法可查看Apple文档)。下面的Ubiquity Containners对SQLite很重要,点加号会自动增加一个Container,够测试用了。

ios开发云存储 apple云存储_SQL_11



12,现在如果没有出现错误,iCloud应该可用了,先在YTAppDelegat.m中增加一个测试iCloud的方法:

#define UBIQUOUTY_CONTAINER_IDENTITY @"TEAM_ID.net.zuoyin.TestiCloud"
@interface YTAppDelegate()
- (BOOL)isiCloudAvailable;
@end
- (BOOL)isiCloudAvailable
{
    NSURL *dbURL=[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:UBIQUOUTY_CONTAINER_IDENTITY];
    if (dbURL)
    {
        return YES;
    }
    else return NO;
}


注意常量定义中的TEAM_ID是形如“179DVMTAP1”这样的字符,可在Provisioning Portal中查找。

然后在application:didFinishLauchingWithOpt ions方法中加入两行代码:
     

if  (self.isiCloudAvailable)  NSLog(@"Good  job!");
        else  NSLog(@"Sorry,You  must  work  harder...");


进行测试,修改后的代码是这样的。

-  (BOOL)application:(UIApplication  *)application  didFinishLaunchingWithOp tions:(NSDictionary  *)launchOptions
{
        //  Override  point  for  customization  after  application  launch.
        if  ([[UIDevice  currentDevice]  userInterfaceIdiom]  ==  UIUserInterfaceIdiomPad)  {
                UISplitViewController  *splitViewController  =  (UISplitViewController  *)self.window.rootViewController;
                UINavigationController  *navigationController  =  [splitViewController.viewControllers  lastObject];
                splitViewController.delegate  =  (id)navigationController.topViewController;
               
                UINavigationController  *masterNavigationControll er  =  splitViewController.viewControllers[0];
                YTMasterViewController  *controller  =  (YTMasterViewController  *)masterNavigationControll er.topViewController;
                controller.managedObjectContext  =  self.managedObjectContext;
        }  else  {
                UINavigationController  *navigationController  =  (UINavigationController  *)self.window.rootViewController;
                YTMasterViewController  *controller  =  (YTMasterViewController  *)navigationController.topViewController;
                controller.managedObjectContext  =  self.managedObjectContext;
        }

    if (self.isiCloudAvailable) NSLog(@"Good job!");
    else NSLog(@"Sorry,You must have made some mistakes...");

       return  YES;
}

确定程序不会产生诸如使显示器爆炸等恶劣后果,运行程序,输出如下图,电脑夸你干得好,说明前面进行的设置没有问题^_^,iCloud可正常使用。现在完成了第一步。

ios开发云存储 apple云存储_ios_12

下面进行第二步:修改persistentStoreCoordinat or方法以增加对iCloud的存取,修改部分我已经加红了。

-  (NSPersistentStoreCoordin ator  *)persistentStoreCoordinat or
{
        if  (_persistentStoreCoordinat or  !=  nil)  {
                return  _persistentStoreCoordinat or;
        }
        NSDictionary *optinotallow=nil;
    if ([self isiCloudAvailable])
    {
         NSURL *dbURL=[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:UBIQUOUTY_CONTAINER_IDENTITY];
        optinotallow=[NSDictionary dictionaryWithObjectsAndKeys:@"net.zuoyin.TestiCloud.SQLite",NSPersistentStoreUbiquitousContentNameKey,dbURL,NSPersistentStoreUbiquitousContentURLKey, nil];
    }
        NSURL  *storeURL  =  [[self  applicationDocumentsDire ctory]  URLByAppendingPathCompon ent:@"TestiCloud.sqlite"];
       
        NSError  *error  =  nil;
        _persistentStoreCoordinat or  =  [[NSPersistentStoreCoordin ator  alloc]  initWithManagedObjectMod el:[self  managedObjectModel]];
        if  (![_persistentStoreCoordinat or  addPersistentStoreWithTy pe:NSSQLiteStoreType  configuration:nil  URL:storeURL options:options  error:&error])  {
                NSLog(@"Unresolved  error  %@,  %@",  error,  [error  userInfo]);
                abort();
        }       
       
        return  _persistentStoreCoordinat or;
}

注意:if  (![_persistentStoreCoordinat or  addPersistentStoreWithTy pe:NSSQLiteStoreType  configuration:nil  URL:storeURL options:options  error:&error]) 新定义的options变量取代了原来的nil。


下面进行第三步:设置iCloud数据变化监听,修改

-  (NSManagedObjectContext  *)managedObjectContext
{
        if  (_managedObjectContext  !=  nil)  {
                return  _managedObjectContext;
        }
       
        NSPersistentStoreCoordin ator  *coordinator  =  [self  persistentStoreCoordinat or];
        if  (coordinator  !=  nil)  {
                NSManagedObjectContext  *managedObjectContext  =  [[NSManagedObjectContext  alloc]
                                                                              initWithConcurrencyType:NSMainQueueConcurrencyTy pe];
               
                [managedObjectContext  performBlockAndWait:^(void){
                       [managedObjectContext  setPersistentStoreCoordi nator:coordinator];                     
           if([self isiCloudAvailable])
            {
                [[NSNotificationCenter defaultCenter] addObserver:self
                                                         selector:@selector(iCloudDataDidChange)
                                                             name:NSPersistentStoreDidImportUbiquitousContentChangesNotification
                                                           object:coordinator];
            }
        }];
                _managedObjectCnotallow=managedObjectContext;
        }
        return  _managedObjectContext;
}

增加相应的调用方法:

//Very very bad code!
- (void)iCloudDataDidChange{
    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
    YTMasterViewController *controller = (YTMasterViewController *)navigationController.topViewController;
    controller.fetchedResultsController=nil;
    [controller fetchedResultsController];
    
    [controller.tableView reloadData];
}
iClo

udDataDidChange方法只是为了测试,千万别在程序中直接这样做(iPad这样更新tableView数据会直接闪退 

ios开发云存储 apple云存储_ios_13

 

ios开发云存储 apple云存储_SQL_14

对了,模拟机上不能进行iCloud测试,所以必须用两台实际的设备进行测试。

运行程序,先在iPad上点击加号,会增加数据。

ios开发云存储 apple云存储_ios_15


等了大约有一分钟,哇!手机上数据更新了,My iCloud!但是怎么只有两行呢?iPad上填加了四行啊?程序问题?网络问题?iCloud问题?还没搞明白。

ios开发云存储 apple云存储_ios_16

抽了根烟,继续等,还是那样。算了,都删掉,再加四行。这次在iPhone上先加:

ios开发云存储 apple云存储_ios_17

这次数据对了(iPad闪退了四次,看来数据是一条一条从iCloud更新回来的 

ios开发云存储 apple云存储_sqlite_18



ios开发云存储 apple云存储_云存储_19




小结:

SQLite(Core Data)进行云存储还是挺简单的,没增加多少代码。当然这只是个测试,具体实现上还会有一些问题,比如我还发现这个测试启动时非常慢(看来启动就测试云是否可用不是好办法)。