Проверьте два NSArrays для содержания объектов друг друга (NSManagedObject) - PullRequest
0 голосов
/ 14 февраля 2012

Я застрял в следующей проблеме: У меня есть два NSArrays, каждый из которых содержит объекты подкласса NSManagedObject. Они питаются из разных источников, но объекты в них все еще имеют те же свойства / значения. Теперь я хочу проверить, содержит ли массив A объекты из массива B и наоборот. К сожалению, метод NSOray containsObject здесь не работает. Я думаю, что он использует id-тестирование для проверки равенства каждого объекта, не так ли?

Итак, у кого-нибудь есть подсказка, что попробовать?

Я даже пытался инкапсулировать свои объекты в NSSets, используя member: в качестве моего метода сравнения, но это также не сработало, особенно потому, что «вы не должны переопределять» isEqual и т. Д. Для подклассов NSManagedObject.

Вот фрагмент кода:

//manufacturers is an array, parsed out of some xml here...

for(Manufacturer *manu in [fetchedResultsController fetchedObjects])
{
    if(![manufacturers containsObject:manu])
    {
        NSLog(@"Deleting %@", manu.name);
        [self.mContext deleteObject:manu];
    }
}

for(Manufacturer *manu in manufacturers)
{
    if(![[fetchedResultsController fetchedObjects] containsObject:manu])
    {
        NSLog(@"Adding %@", manu.name);
        [newArray addObject:manu];
    }
}

Заранее спасибо за любую подсказку;)

Ответы [ 3 ]

0 голосов
/ 14 февраля 2012

Существует три типа равенства, которые вы можете проверить: один и тот же адрес памяти, равенство идентификатора управляемого объекта и равенство значений. Ваш текущий код уже проверяет, имеют ли объекты тот же адрес памяти, и это, скорее всего, не то, что вас интересует. Это оставляет два возможных варианта. Используя метод равенства идентификаторов управляемых объектов, вы можете проверить, указывают ли производители на одну и ту же строку в базе данных. Используя равенство значений, вы можете проверить, равны ли два производителя на основе общих значений. Ниже приведен способ проверки на равенство NSManagedObjectID.

for(Manufacturer *manu in [fetchedResultsController fetchedObjects])
{
    id databaseIDTest = ^(Manufacturer * checkManu, NSUInteger idx, BOOL *stop){
        return [[checkManu objectID] isEqual:[manu objectID]];
    };

    if([manufacturers indexOfObjectPassingTest:databaseIDTest] == NSIndexNotFound)
    {
        NSLog(@"Deleting %@", manu.name);
        [self.mContext deleteObject:manu];
    }
}

for(Manufacturer *manu in manufacturers)
{
    id databaseIDTest = ^(Manufacturer * checkManu, NSUInteger idx, BOOL *stop){
        return [[checkManu objectID] isEqual:[manu objectID]];
    };
    NSArray * fetchedObjects = [fetchedResultsController fetchedObjects];
    if([fetchedObjects indexOfObjectPassingTest:databaseIDTest] == NSIndexNotFound)
    {
        NSLog(@"Adding %@", manu.name);
        [newArray addObject:manu];
    }
}
0 голосов
/ 15 февраля 2012

Вам необходимо переопределить -isEqual:, поскольку -[NSArray containsObject:] вызывает следующее:

- (BOOL)isEqual:(id)other;
{
    if (![other isKindOfClass:[Manufacturer class]]) {
        return NO;
    }
    Manufacturer *otherManufacturer = other;
    return ([self.name isEqual:otherManufacturer.name] &&
           ...
           );
}

Проверка на содержание внутри NSSet обходится дешевле (и может иметь смысл, если вы столкнетесь с проблемами производительности).Это работает, только если у вас есть относительно приличная реализация -hash, но ее легко реализовать следующим образом:

- (NSUInteger)hash;
{
    return [self.name hash] + [self.foo hash] + ...;
}

Не пытайтесь решить слишком много проблем с хэшем, просто используйте 2-3 значения, которые наиболее вероятно для уникальной идентификации объекта.

0 голосов
/ 14 февраля 2012

Я не уверен, что это работает, но вы можете попробовать сопоставить словари, которые вы получаете с dictionaryWithValuesForKeys:.

Примерно так:

NSArray *keysToCompare = [NSArray arrayWithObjects:@"FooAttribute", @"BarAttribute", nil];

// create an array with the dictionary representation of the managedObject
NSMutableArray *fetchedObjectsDictionaries = [NSMutableArray arrayWithCapacity:[[fetchedResultsController fetchedObjects] count]];
for (NSManagedObject *object in [fetchedResultsController fetchedObjects]) {
    NSDictionary *dictionaryRepresentation = [object dictionaryWithValuesForKeys:keysToCompare];
    [fetchedObjectsDictionaries addObject:dictionaryRepresentation];
}

// another array with dictionaries for managedObjects
NSMutableArray *manufacturersDictionaries = [NSMutableArray arrayWithCapacity:[manufacturers count]];
for (NSManagedObject *object in manufacturers) {
    NSDictionary *dictionaryRepresentation = [object dictionaryWithValuesForKeys:keysToCompare];
    [manufacturersDictionaries addObject:dictionaryRepresentation];
}

// compare those dictionaries
for (NSInteger i = 0; i < [fetchedObjectsDictionaries count]; i++) {
    NSDictionary *dictionary = [fetchedObjectsDictionaries objectAtIndex:i];
    if (![manufacturersDictionaries containsObject:dictionary]) {
        // get the corresponding managedObject
        NSManagedObject *object = [[fetchedResultsController fetchedObjects] objectAtIndex:i];
        [newArray addObject:object];
    }
}

еслиэто не сработает, вы можете написать свой собственный метод isEqualToManufacturer: и перечислить массивы вручную.

...