请注意:这与this question不是同一个问题,因为我已经知道这源于Apple漏洞。请注意,覆盖特定方法(例如,-addFriendsObject:
如果我有朋友关系)不是一个选项,因为我需要在一个类别中执行此操作,因此它适用于任何托管对象,无论修改模型和从中重建自动生成的类。
对此的需求源于这样一个事实:显然,分钟关系是有序的,而且很多(NSMutableOrderedSets)核心数据的动态方法是地狱:
-add<Relationship>Object
,-add<Relationship>
,-remove<Relationship>Object
和-remove<Relationship>
都会因类似异常而崩溃'NSInvalidArgumentException', reason: '*** -[NSSet intersectsSet:]: set argument is not an NSSet'
insertObject:in<Relationship>AtIndex:
行的方法将会崩溃,因为CoreData实际上没有提供它们的实现。至于 2 ,我写了一个覆盖-methodSignatureForSelector:
和-forwardInvocation
的类别,而不是像mutableOrderedSetValueForKey
这样的关系名称,后跟实际添加或删除。
现在对于 1 ,问题是CoreData实际上为这些方法提供了实现(尽管它们不是有序集的正确实现)。所以我需要一种拦截那些选择器的方法,所以我可以通过mutableOrderedSetValueForKey实现这个行为。
任何想法如何实现它?
答案 0 :(得分: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