首次运行的逻辑应该是什么,互联网可用?

时间:2013-04-13 20:14:54

标签: ios core-data

对于从Web服务获取Web的应用程序,我已经包含了一个要在第一次运行时解析到CoreData中的plist,因为Docs目录中的数据不可用,或者可能需要很长时间才能从Web获取。当网络提取/同步成功时,我确实有NSNotifications信令。

目前在AppDelegate applicationDidFinishLaunchingWithOptions中我打电话:

[self checkIfFirstRun];

这是:

-(void)checkIfFirstRun{
    NSString *bundleVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
    NSString *appFirstStartOfVersionKey = [NSString stringWithFormat:@"first_start_%@", bundleVersion];
    NSNumber *alreadyStartedOnVersion = [[NSUserDefaults standardUserDefaults] objectForKey:appFirstStartOfVersionKey];

    if(!alreadyStartedOnVersion || [alreadyStartedOnVersion boolValue] == NO) {
        // IF FIRST TIME -> Preload plist data
        UIAlertView *firstRun = [[UIAlertView alloc] initWithTitle:@"1st RUN USE LOCAL DB"
                                                                message:@"FIRST"
                                                               delegate:self
                                                      cancelButtonTitle:@"Cancel"
                                                      otherButtonTitles:@"Ok", nil];
        [firstRun show];
        NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        [prefs setObject:[NSNumber numberWithBool:YES] forKey:appFirstStartOfVersionKey];
        [prefs synchronize];

        //Use plist
        [self parsePlistIntoCD];

    } else {
        UIAlertView *secondRun = [[UIAlertView alloc] initWithTitle:@"nTH RUN WEB FETCH"
                                                           message:@"nTH"
                                                          delegate:self
                                                 cancelButtonTitle:@"Cancel"
                                                 otherButtonTitles:@"Ok", nil];
        [secondRun show];


    }
}

好吧,我把我的plist完全解析为我的CoreData数据库。

这是parsePlistIntoCD:

-(void)parsePlistIntoCD{
    self.managedObjectContext = [[SDCoreDataController sharedInstance] backgroundManagedObjectContext];
    // 3: Now put the plistDictionary into CD...create get ManagedObjectContext
    NSManagedObjectContext *context = self.managedObjectContext;
    NSError *error;

    //Create Request & set Entity for request
    NSFetchRequest *holidayRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *topicEntityDescription = [NSEntityDescription entityForName:@"Holiday" inManagedObjectContext:context];
    [holidayRequest setEntity:topicEntityDescription];

    //Create new NSManagedObject
    //Holiday *holidayObjectToSeed = nil;
    Holiday *newHoliday = nil;
    //Execute fetch just to make sure?
    NSArray *holidayFetchedArray = [context executeFetchRequest:holidayRequest error:&error];
    if (error) NSLog(@"Error encountered in executing topic fetch request: %@", error);

    // No holidays in database so we proceed to populate the database
    if ([holidayFetchedArray count] == 0) {
        //Get path to plist file
        NSString *holidaysPath = [[NSBundle mainBundle] pathForResource:@"PreloadedFarsiman" ofType:@"plist"];
        //Put data into an array (with dictionaries in it)
        NSArray *holidayDataArray = [[NSArray alloc] initWithContentsOfFile:holidaysPath];
        NSLog(@"holidayDataArray is %@", holidayDataArray);
        //Get number of items in that array
        int numberOfTopics = [holidayDataArray count];
        //Loop thru array items...
        for (int i = 0; i<numberOfTopics; i++) {
            //get each dict at each node
            NSDictionary *holidayDataDictionary = [holidayDataArray objectAtIndex:i];
            //Insert new object
            newHoliday = [NSEntityDescription insertNewObjectForEntityForName:@"Holiday" inManagedObjectContext:context];
            //Parse all keys in each dict object
            [newHoliday setValuesForKeysWithDictionary:holidayDataDictionary];
            //Save and or log error
            [context save:&error];
            if (error) NSLog(@"Error encountered in saving topic entity, %d, %@, Hint: check that the structure of the pList matches Core Data: %@",i, newHoliday, error);
        };
    }
    [[SDSyncEngine sharedEngine] startSync];

}

问题是,我还需要确保如果有可用的互联网,我的CoreData数据库会被获取的网络数据重新填充。

但如果我将电话留给[self parsePlistIntoCD];只有plist数据存在于CoreData中。第一次或第n次运行,我只得到plist数据。如果我评论该行,我会获取我的网络获取数据。

为什么Web获取的数据不会替换plist解析数据?

1 个答案:

答案 0 :(得分:1)

所以parsePlistIntoCD的逻辑基本上是

  • 如果商店中没有对象,请从plist
  • 加载它们
  • 始终在startSync上调用[SDSyncEngine sharedEngine]startSync处理网络下载和同步。

我认为你的 BOOL alreadyStartedOnVersion = [[NSUserDefaults standardUserDefaults] boolForKey:appFirstStartOfVersionKey]; 实际上会被调用。所以我会在那里看看这个bug。您可以添加日志语句或设置断点,以验证是否实际遵循了该代码路径。

plist解析和Web数据提取可能需要一些时间。这表明您应该在后台执行这些操作,可能使用GCD队列。你事先并不知道他们中的任何一个是否会成功。因此,在完成之前不要设置首选项。

附注:您可以查询首选项数据库中的BOOL,使您的代码更短,因此更易于阅读。

    [prefs setBool:YES forKey:appFirstStartOfVersionKey];            

numberWithBool:

您也可以仅使用@(YES)@(NO)替换-applicationDidFinishLaunchingWithOptions:

对于你的程序逻辑,我建议像这样:

  • shouldLoadPlistData中,检查是否已加载起始plist数据。忘掉它是否是第一次运行。只需查看是否需要加载plist数据。也许称之为latestPlistVersionLoaded。或者您可能需要将其与正在运行的版本联系起来,在这种情况下,您将存储字符串shouldLoadPlistData
  • 如果尚未加载,请将块排入队列以执行plist加载。在plist加载结束时,将NO设置为parseListIntoCD,注意不再需要加载plist数据。如果由于某种原因,plist加载失败(可能是手机电量耗尽或者你的应用程序被用户或系统杀死),那么在下次启动时你就会回到你开始的地方。
  • 还要检查您是否有网络访问权限。如果这样做,请将块排入队列以检索基于Web的数据,解析数据,然后在结束时更新首选项。

如果数据很大,您可能需要检查此工作:

  • 我是否拥有完整的网络更新?然后我就完成了。否则...
  • 下载完成了吗?是的,我有数据,让我们加载它。
  • 如果没有,我是否开始下载?

如果您的应用程序在下载过程中退出,此阶段检查点还可让您向系统询问额外时间。

shouldLoadPlist对我来说有点臃肿。它的名字不仅仅是它的意思。也许你可以将它重构为一个支票(importPlist:intoContext:),一个执行导入的方法(NSManagedObjectContext),以及一个触发同步的方法。

我强烈建议您将工作[SDCoreDataController sharedInstance]作为参数传递,而不是让一些全局对象分配MOC(如NSError **所示。)它为您提供了更多控制,并允许你可以更容易地编写单元测试。如果你也传递了plist的路径,那么你现在拥有干净的代码,每次调用它时都应该采用相同的方式。

您对if (![someObject doTaskWithObject:foo error:&error]) { // handle the error } 参数的使用始终不正确。成功时,NSError的值未定义。您必须测试操作的结果,而不是错误的值,以确定您是否成功。这个成语总是

countForFetchRequest:error

另请参阅{{1}}。通过执行获取和计数结果,它将为您提供当前正在提取的相同信息,但无需实例化NSManagedObjects。