【发布时间】: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