ios - 具有核心数据的具有挑战性的在线数据库持久性?

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

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

以下方法从下拉列表中调用以在 TableView Controller 上刷新。

- (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];
    }
    }
}

最佳答案

在注释标记的分支中 //本地数据库中没有运动员匹配任何在线运动员 您正在创建一个新的 PFObject 并将其保存到 Parse。以我的理解,这不应该是正确的,因为运动员不在本地数据库中而是在线。

关于ios - 具有核心数据的具有挑战性的在线数据库持久性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22582362/

相关文章:

ios - UICollectionViewDropDelegate 破坏了 UICollectionView 中的重新排序单元机制

ios - 80 年代的 4 月 1 日日期在 iOS 10.0 中无法解析

objective-c - 像在 HTML 中一样访问 UI 输入元素

c++ - C++ 和 Objective C 之间的事件处理

objective-c - 使复选框不可编辑

objective-c - didSelectRowAtIndexPath 一次选择多行

objective-c - Xcode 在整个屏幕上添加 subview 高于一切

ios - 展开后 swift subview 不更新

ios - 设计模块化 iOS 项目的建议?

iphone - 像 Facebook 应用程序一样的 UITableView