4

请注意:这与此问题不同,因为我已经知道这源于 Apple 错误。请注意,重写特定方法(例如,-addFriendsObject:如果我有朋友关系)不是一种选择,因为我需要在一个类别中执行此操作,因此它适用于任何托管对象,无论修改模型和重建自动生成的类它。

对此的需求源于这样一个事实,即显然一分钟使关系有序,并且对多(NSMutableOrderedSets)核心数据动态方法陷入困境:

  1. 方法-add<Relationship>Object,-add<Relationship>和都将崩溃-remove<Relationship>Object-remove<Relationship>出现类似的异常'NSInvalidArgumentException', reason: '*** -[NSSet intersectsSet:]: set argument is not an NSSet'
  2. 类似的方法insertObject:in<Relationship>AtIndex:将会崩溃,因为 CoreData 实际上没有为它们提供任何实现。

2而言,我编写了一个覆盖-methodSignatureForSelector:-forwardInvocation改为mutableOrderedSetValueForKey对关系名称执行类似操作的类别,然后是实际添加或删除。

现在对于1,问题在于 CoreData 实际上为这些方法提供了实现(尽管它们不是有序集合的正确实现)。所以我也需要一种拦截这些选择器的方法,这样我就可以通过 mutableOrderedSetValueForKey 实现该行为。

有什么想法可以解决吗?

4

1 回答 1

0

我不知道这是最好的方法(它肯定不是最漂亮的东西),但它完成了工作:

#import "NSManagedObject+OrderedSets.h"
#import <objc/runtime.h>

@implementation NSManagedObject (OrderedSets)

+ (void)swizzleMethod:(SEL)originalSelector with:(SEL)replacementSelector
{
    const char *methodTypeEncoding = method_getTypeEncoding(class_getInstanceMethod([self class], originalSelector));
    class_replaceMethod(self,
                        originalSelector,
                        class_getMethodImplementation(self, replacementSelector),
                        methodTypeEncoding);
}

+ (void)initialize
{
    NSEntityDescription *selfEntity = // get a hold of your NSManagedObjectContext and from its entities grab model.entitiesByName[NSStringFromClass(self)] ... 
    for (NSString *rKey in [selfEntity relationshipsByName]) {
        NSRelationshipDescription *r = selfEntity.relationshipsByName[rKey];
        if (r.isOrdered) {
            NSString *rKeyFirstCaps = [[rKey substringToIndex:1] capitalizedString];
            NSString *capitalizedKey = [rKey stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:rKeyFirstCaps];
            NSString *addSelectorString = [NSString stringWithFormat:@"add%@Object:", capitalizedKey];
            NSString *removeSelectorString = [NSString stringWithFormat:@"remove%@Object:", capitalizedKey];
            [self swizzleMethod:NSSelectorFromString(addSelectorString) with:@selector(addOrRemoveObjectInOrderedSet:)];
            [self swizzleMethod:NSSelectorFromString(removeSelectorString) with:@selector(addOrRemoveObjectInOrderedSet:)];
        }
    }
}

- (void)addOrRemoveObjectInOrderedSet:(NSManagedObject*)object
{
    NSString *selectorString = NSStringFromSelector(_cmd);
    NSString *prefix = [selectorString hasPrefix:@"add"] ? @"add" : @"remove";
    selectorString = [selectorString stringByReplacingCharactersInRange:[selectorString rangeOfString:prefix] withString:@""];
    selectorString = [selectorString stringByReplacingCharactersInRange:[selectorString rangeOfString:@"Object" options:NSBackwardsSearch] withString:@""];
    selectorString = [selectorString substringToIndex:selectorString.length - 1];
    NSString *selectorFirstLowerCase = [[selectorString substringToIndex:1] lowercaseString];
    NSString *camelCasedKey = [selectorString stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:selectorFirstLowerCase];

    if ([prefix isEqualToString:@"add"]) {
        [[self mutableOrderedSetValueForKey:camelCasedKey] addObject:object];
    }
    else {
        [[self mutableOrderedSetValueForKey:camelCasedKey] removeObject:object];
    }
}

@end
于 2013-05-29T06:05:40.103 回答