【问题标题】:Challenging Online Database Persistence w/ Core Data?使用核心数据挑战在线数据库持久性?
【发布时间】:2014-03-22 19:21:15
【问题描述】:

这是我第一次在网上做任何与数据库持久性/维护有关的工作,所以我提前为我的草率代码道歉。我的应用程序包含用户创建一群运动员并将他们的数据保存在网上,以便可以从任何设备访问它们。这非常有效,除了运动员每个人都在网上保存了两次,这让我想把头发扯掉。我已经检查了我的代码数百次,但我似乎无法找到为什么运动员在服务器上被保存两次,导致本地也有 2 次。我正在使用 Parse.com 框架。我错过了什么吗?

从下拉列表中调用以下方法以刷新表格视图控制器。

- (void)getParseData {
    NSLog(@"GET PARSE DATA WAS CALLED");
    if(self.syncing != TRUE){
        NSLog(@"GET PARSE DATA RAN");
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateStyle = NSDateFormatterLongStyle;

    PFQuery *query = [PFQuery queryWithClassName:@"Athlete"];

    [self populateAthleteArray];

    if (self.athleteArray.count == 0) {
        NSLog(@"ATHLETE ARRAY IS EMPTY");
        // If the athlete array has no objects, download all objects from the database.

        [query findObjectsInBackgroundWithBlock: ^(NSArray *objects, NSError *error) {
            self.syncing = TRUE;
            if (!error) {
                self.syncing = FALSE;
                for (PFObject * object in objects) {
                    Athlete *newAthlete = [NSEntityDescription insertNewObjectForEntityForName:@"Athlete" inManagedObjectContext:_managedObjectContext];

                    newAthlete.first = object[@"first"];
                    newAthlete.last = object[@"last"];
                    newAthlete.updatedAt = [dateFormatter stringFromDate:[object updatedAt]];
                    newAthlete.objectId = [object objectId];

                    [_managedObjectContext save:nil];
                }
                self.syncing = FALSE;
            }
            else {
                self.syncing = FALSE;
                NSLog(@"Error: %@ %@", error, [error userInfo]);
            }
            if(self.needToUploadArray.count > 0){
                [PFObject saveAllInBackground:self.needToUploadArray target:nil selector:@selector(emptyUploadArray)];
            }
        }];
        [self populateAthleteArray];
        [self.tableView reloadData];
    }
    else {
        NSLog(@"ATHLETE ARRAY HAS ATHLETES ALREADY");
        // Athlete array has athletes already

        NSMutableArray *athletesToUpload = [NSMutableArray array];
        // Placeholder array for athletes that aren't in the database.

        for (Athlete *athlete in athleteArray) {
            if (athlete.objectId.length == 0 || athlete.objectId == nil) {
                // If the objectId is nil, it wasn't uploaded to the database. Add to placeholder array.
                [athletesToUpload addObject:athlete];
            }
        }

        [query findObjectsInBackgroundWithBlock: ^(NSArray *objects, NSError *error) {
            self.syncing = TRUE;
            if (!error) {
                // Downloaded all athletes successfully
                self.syncing = FALSE;
                BOOL found = FALSE;

                [self populateAthleteArray];

                NSMutableArray *athletesToDelete = [NSMutableArray array];

                for (Athlete * athlete in athleteArray) {

                    for (PFObject * object in objects) {
                        // Check to see each local athlete exists in the online database
                        if ([object.objectId isEqualToString:athlete.objectId]) {
                            // Athlete was find in the online database
                            found = TRUE;
                            break;
                        }
                    }
                    if (found != TRUE) {
                        NSLog(@"%@ was not found online.",athlete.first);
                        if(athlete.objectId.length > 0){
                            NSLog(@"%@ was deleted online. delete them locally",athlete.first);
                            [athletesToDelete addObject:athlete];
                        }
                        else{
                            // No athlete in the local database matched any of the athletes online

                            PFObject *onlineAthlete = [PFObject objectWithClassName:@"Athlete"];
                            onlineAthlete[@"first"] = athlete.first;
                            onlineAthlete[@"last"] = athlete.last;
                            PFFile *imageFile = [PFFile fileWithName:[NSString stringWithFormat:@"%@%@MedicalRelease.jpg", athlete.first, athlete.last] data:athlete.medical_release_image];
                            onlineAthlete[@"medical_release_image"] = imageFile;



                            [onlineAthlete saveInBackgroundWithBlock: ^(BOOL succeeded, NSError *error) {
                                self.syncing = TRUE;
                                if (succeeded) {
                                    NSLog(@"SAVED SUCCESSFULLY");
                                    self.syncing = FALSE;
                                    PFQuery *query = [PFQuery queryWithClassName:@"Athlete"];
                                    [query orderByDescending:@"createdAt"];
                                    [query getFirstObjectInBackgroundWithBlock: ^(PFObject *object, NSError *error) {
                                        Athlete *athleteToChange = [self findAthlete:athlete.objectId];
                                        [athleteToChange setObjectId:[object objectId]];
                                        [_managedObjectContext save:nil];
                                    }];
                                }
                            }];
                        }
                    }
                    found = FALSE;
                }

                if(athletesToDelete.count > 0){
                    for(id athlete in athletesToDelete){
                        NSManagedObject *eventToDelete = athlete;
                        [_managedObjectContext deleteObject:eventToDelete];
                        [athleteArray removeObjectAtIndex:[athleteArray indexOfObject:athlete]];
                        [self.tableView reloadData];
                        NSError *error = nil;
                        if (![_managedObjectContext save:&error]) {
                            NSLog(@"there is an error: %@", error);
                        }
                    }
                }

                for (PFObject *object in objects) {
                    // Loop through every athlete downloaded

                    for (Athlete * athlete in athleteArray) {
                        // For every object downloaded, compare it to every athlete in the local database.

                        if ([object.objectId isEqualToString:athlete.objectId]) {
                            // If the object's id matches the local athletes id, we found the object
                            if ([object updatedAt] >= [dateFormatter dateFromString:athlete.updatedAt]) {
                                // If the object has been updated more recently than the athlete, update the local athlete

                                Athlete *sameAthlete = [self findAthlete:athlete.objectId];

                                sameAthlete.first = object[@"first"];
                                sameAthlete.last = object[@"last"];
                                sameAthlete.updatedAt = [dateFormatter stringFromDate:[object updatedAt]];
                                sameAthlete.address = object[@"address"];
                                sameAthlete.objectId = [object objectId];
                                [_managedObjectContext save:nil];
                            }
                            found = TRUE;
                            // The athlete was found in the database
                            break;
                        }
                    }
                    if (found != TRUE) {
                        // We looped through all the local athletes, the object downloaded isn't in the local database; add them.

                        Athlete *athlete = [NSEntityDescription insertNewObjectForEntityForName:@"Athlete" inManagedObjectContext:_managedObjectContext];
                        athlete.first = object[@"first"];
                        athlete.last = object[@"last"];
                        athlete.objectId = [object objectId];
                        athlete.address = object[@"address"];
                        athlete.updatedAt = [dateFormatter stringFromDate:[object updatedAt]];
                        [_managedObjectContext save:nil];
                    }
                    // Reset flag var
                    found = FALSE;
                }


            }
            else {
                self.syncing = FALSE;
                NSLog(@"Error: %@ %@", error, [error userInfo]);
            }
            self.syncing = FALSE;
        }];

        if (athletesToUpload.count > 0) {
            for (Athlete *athlete in athletesToUpload) {
                PFObject *upload = [PFObject objectWithClassName:@"Athlete"];
                upload[@"first"] = athlete.first;
                upload[@"last"] = athlete.last;
                PFFile *imageFile = [PFFile fileWithName:[NSString stringWithFormat:@"%@%@MedicalRelease.jpg", athlete.first, athlete.last] data:athlete.medical_release_image];
                upload[@"medical_release_image"] = imageFile;
                [upload saveInBackgroundWithBlock: ^(BOOL succeeded, NSError *error) {
                    if (succeeded) {
                        PFQuery *uploadQuery = [PFQuery queryWithClassName:@"Athlete"];
                        [uploadQuery orderByDescending:@"createdAt"];
                        [uploadQuery getFirstObjectInBackgroundWithBlock: ^(PFObject *object, NSError *error) {
                            [athlete setObjectId:[object objectId]];
                        }];
                    }
                }];
            }
        }

        [self populateAthleteArray];
        [self.tableView reloadData];
    }
    }
}

【问题讨论】:

  • 这是很多代码,但乍一看,我注意到您正在手动缓存结果,这对于 parse 的框架来说似乎是不必要的。您可以为您的查询设置缓存策略,并为您处理所有这些问题。
  • 另外,您应该只在应用委托中设置一次解析 applicationId 和 clientKey。你不应该在每次运行这样的方法时都重置它。
  • 好点Logan,我现在会努力的。

标签: ios objective-c cocoa-touch core-data parse-platform


【解决方案1】:

在注释 // No athlete in the local database matched any of the athletes online 标记的分支中,您正在创建一个新的 PFObject 并将其保存到 Parse。据我了解,这应该是不正确的,因为运动员不在本地数据库中,而是在线。

【讨论】:

  • 第一个 for 循环检查运动员是否在本地,但不在线。第二个 for 循环检查运动员是否在线但不在本地。
  • 我明白了。问题可能与needToUploadArray 有关吗?我没有找到它是如何填充到您的 sn-p 中的...除此之外,我建议在本地数据库为空时逐步执行该方法,然后再执行一次(因此您检查当它不为空时会发生什么) .你应该很容易知道发生了什么。
猜你喜欢
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-16
相关资源
最近更新 更多