swa*_*ner 10 objective-c ios5 kvc
我有一个类型的对象,id
并想知道它是否包含给定的值keyPath
:
[myObject valueForKeyPath:myKeyPath];
Run Code Online (Sandbox Code Playgroud)
现在,我将它包装到一个@try{ } @catch{}
块中,以避免在找不到给定的keypath时出现异常.有没有更好的方法来做到这一点?检查给定的密钥路径是否存在而不处理异常?
非常感谢,
斯特凡
你可以试试这个:
if ([myObject respondsToSelector:NSSelectorFromString(myKeyPath)])
{
}
Run Code Online (Sandbox Code Playgroud)
但是,这可能与您拥有的getter不对应,特别是如果它是布尔值.如果这不适合你,请告诉我,我会用反射给你写一些东西.
因为NSManagedObjects
,一个简单的解决方案是查看对象的实体描述,看看是否有一个具有该键名的属性.如果有,您还可以将其带到下一步,并查看该值的属性类型.
这是一个简单的方法,给出任何NSManagedObject
和任何NSString
作为键,将始终返回NSString
:
- (NSString *)valueOfItem:(NSManagedObject *)item asStringForKey:(NSString *)key {
NSEntityDescription *entity = [item entity];
NSDictionary *attributesByName = [entity attributesByName];
NSAttributeDescription *attribute = attributesByName[key];
if (!attribute) {
return @"---No Such Attribute Key---";
}
else if ([attribute attributeType] == NSUndefinedAttributeType) {
return @"---Undefined Attribute Type---";
}
else if ([attribute attributeType] == NSStringAttributeType) {
// return NSStrings as they are
return [item valueForKey:key];
}
else if ([attribute attributeType] < NSDateAttributeType) {
// this will be all of the NSNumber types
// return them as strings
return [[item valueForKey:key] stringValue];
}
// add more "else if" cases as desired for other types
else {
return @"---Unacceptable Attribute Type---";
}
}
Run Code Online (Sandbox Code Playgroud)
如果密钥无效或者值无法生成字符串,则该方法返回NSString
错误消息(将这些块更改为对这些情况执行任何操作).
所有NSNumber
属性类型都作为其stringValue
表示形式返回.要处理其他属性类型(例如:日期),只需添加其他"else if"块.(NSAttributeDescription
有关更多信息,请参阅类参考).
应该可以相当简单地将这种行为移植到任意类上。我充满信心地(但没有保证)提供以下代码,您应该能够使用它来向任何类添加非异常抛出的实现valueForUndefinedKey:
,并在应用程序启动时为每个类添加一行集中的代码。如果您想节省更多代码,您可以使所有您想要具有此行为的类继承自 NSManagedObject 的公共子类,然后将其应用于该公共类,并且您的所有子类都将继承该行为。之后有更多详细信息,但这是代码:
标题 ( NSObject+ValueForUndefinedKeyAdding.h
):
@interface NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler;
@end
Run Code Online (Sandbox Code Playgroud)
执行 (NSObject+ValueForUndefinedKeyAdding.m
):
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import <objc/runtime.h>
#import <objc/message.h>
@implementation NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler
{
Class clazz = self;
if (clazz == nil)
return;
if (clazz == [NSObject class] || clazz == [NSManagedObject class])
{
NSLog(@"Don't try to do this to %@; Really.", NSStringFromClass(clazz));
return;
}
SEL vfuk = @selector(valueForUndefinedKey:);
@synchronized([NSObject class])
{
Method nsoMethod = class_getInstanceMethod([NSObject class], vfuk);
Method nsmoMethod = class_getInstanceMethod([NSManagedObject class], vfuk);
Method origMethod = class_getInstanceMethod(clazz, vfuk);
if (origMethod != nsoMethod && origMethod != nsmoMethod)
{
NSLog(@"%@ already has a custom %@ implementation. Replacing that would likely break stuff.",
NSStringFromClass(clazz), NSStringFromSelector(vfuk));
return;
}
if(!class_addMethod(clazz, vfuk, handler, method_getTypeEncoding(nsoMethod)))
{
NSLog(@"Could not add valueForUndefinedKey: method to class: %@", NSStringFromClass(clazz));
}
}
}
@end
Run Code Online (Sandbox Code Playgroud)
然后,在您的 AppDelegate 类中(或者任何地方,但将其放在中心位置可能是有意义的,这样当您想要从列表中添加或删除类时,您知道在哪里可以找到它)将此代码添加到类中您在启动时选择的:
#import "MyAppDelegate.h"
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import "MyOtherClass1.h"
#import "MyOtherClass2.h"
#import "MyOtherClass3.h"
static id ExceptionlessVFUKIMP(id self, SEL cmd, NSString* inKey)
{
NSLog(@"Not throwing an exception for undefined key: %@ on instance of %@", inKey, [self class]);
return nil;
}
@implementation MyAppDelegate
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[MyOtherClass1 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass2 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass3 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
});
}
// ... rest of app delegate class ...
@end
Run Code Online (Sandbox Code Playgroud)
我在这里所做的是为valueForUndefinedKey:
类 MyOtherClass1、2 和 3 添加自定义实现。我提供的示例实现仅NSLog
s 并返回 nil,但您可以通过更改代码来更改实现以执行您想要的任何操作在ExceptionlessVFUKIMP
。如果您删除NSLog
,然后返回 nil,我怀疑根据您的问题您会得到您想要的。
这段代码永远不会混合方法,它只会在不存在的情况下添加一个。我已经进行了检查,以防止在已经具有自己的自定义实现的类上使用此valueForUndefinedKey:
方法,因为如果有人将该方法放入其类中,则会期望它将继续被调用。另请注意,可能有 AppKit 代码期望从 NSObject/NSManagedObject 实现中抛出异常。(我不确定,但可以考虑。)
NSManagedObject
valueForUndefinedKey:
为在调试器中单步执行其程序集提供了一个自定义实现,它所做的只是抛出大致相同的异常,但消息略有不同。基于 5 分钟的调试器调查,我觉得在NSManagedObject
子类中使用它应该是安全的,但我不是 100% 确定——其中可能存在一些我没有发现的行为。谨防。
另外,就目前情况而言,如果您使用这种方法,您没有一个好的方法来知道是否因为 keyPath 有效且状态恰好为 而valueForKey:
返回,或者是否因为 keyPath 无效且嫁接而返回处理程序返回零。为此,您需要做一些不同的、特定于实现的事情。(也许返回或其他一些哨兵值,或者在线程本地存储中设置一些您可以检查的标志,但此时它真的比 容易得多吗?)只是需要注意的事情。nil
nil
nil
[NSNull null]
@try/@catch
这对我来说似乎很有效;希望它对您有用。
归档时间: |
|
查看次数: |
6772 次 |
最近记录: |