Handling duplicate entries in Core Data

前端 未结 6 492
野的像风
野的像风 2021-02-04 10:28

I have an app that allows users to save favorites. I am using Core Data to store the favorites as managed objects. I have written some code to prevent the possibility of storing

6条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-02-04 10:48

    If you're dealing with multiple records, iterating over a count fetch or retrieving actual objects is VERY costly on the CPU. In my case, I did one fetch for all matching records, but asked for a dictionary of just the string of the UUID back. Saves a lot of CPU overhead.

    For example, I have a uUID property on every record in core data. I have a corresponding UUID listed as @"UUID" in CloudKit.

      //1. Create a request for the entity type, returning an array of dictionaries  
          NSFetchRequest* request = [NSFetchRequest fetchRequestWithEntityName:@"someEntityName"];
          [request setResultType:NSDictionaryResultType];
          [request setReturnsDistinctResults:YES];
          [request setPropertiesToFetch: @[@"uUID"]];
    
      //2. Create an array of UUID strings of the downloaded objects
          NSMutableArray *UUIDstrings = [NSMutableArray new];
          for (CKRecord *record in ckRecords) {
            [UUIDstrings addObject:record[@"UUID"]];
          }
    
       //3. Create a predicate to find any Core Data objects with the same UUID
          [request setPredicate:[NSPredicate predicateWithFormat:@"uUID in %@", UUIDstrings]];
    
       //4. If there are results from the fetch, do a log and you'll see it's a dictionary. 
          NSArray *deck = [self.MOC executeFetchRequest:request error:nil];
    
          NSLog(@"Logging the result of index 0. Should be a dictionary %@", deck.count > 0 ? [deck objectAtIndex:0] : @"No results");
    
       //5. Then either do an embedded fast enumeration (for xx in xx){for xx in xx} to find a match like         
    
               if ([(NSString *)record[@"UUID"] isEqualToString:[dict valueForKey:@"uUID"]]) 
              {do something}
    
       //...Or 6. Use a more linear approach with NSSet
    
        //Harvest the core data strings
          NSMutableArray *coreDataStrings = [NSMutableArray new];
            for (NSDictionary *dict in deck) {
            [coreDataStrings addObject:[dict objectForKey:@"uUID"]];
          }
    
       //Create a set of your downloaded objects
          NSSet *arraySet = [NSSet setWithArray:ckRecords];
    
       //Then use a predicate search - a NOT version of above
         NSArray *final = [[arraySet filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"NOT(UUID in %@)", coreDataStrings]]allObjects];
    

    The console log of the dictionary will look something like this. Just the smallest amount of info required to match:

    dictionary {
       uUID = "AFACB8CE-B29E-4A03-9284-4BD5F5464";
    }
    

    More here at the developer site on finding unique values.

提交回复
热议问题