mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-24 04:46:01 +08:00
Take KVC scalar/structure support and NSAttributeType into account when inspecting properties.
This commit is contained in:
@@ -44,7 +44,11 @@ RK_FIX_CATEGORY_BUG(RKPropertyInspector_CoreData)
|
||||
for (NSString *name in [entity attributesByName]) {
|
||||
NSAttributeDescription *attributeDescription = [[entity attributesByName] valueForKey:name];
|
||||
if ([attributeDescription attributeValueClassName]) {
|
||||
[propertyNamesAndTypes setValue:NSClassFromString([attributeDescription attributeValueClassName]) forKey:name];
|
||||
Class cls = NSClassFromString([attributeDescription attributeValueClassName]);
|
||||
if ([cls isSubclassOfClass:[NSNumber class]] && [attributeDescription attributeType] == NSBooleanAttributeType) {
|
||||
cls = objc_getClass("NSCFBoolean") ?: objc_getClass("__NSCFBoolean") ?: cls;
|
||||
}
|
||||
[propertyNamesAndTypes setValue:cls forKey:name];
|
||||
|
||||
} else if ([attributeDescription attributeType] == NSTransformableAttributeType &&
|
||||
![name isEqualToString:@"_mapkit_hasPanoramaID"]) {
|
||||
@@ -53,12 +57,10 @@ RK_FIX_CATEGORY_BUG(RKPropertyInspector_CoreData)
|
||||
const char *propertyName = [name cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
Class managedObjectClass = objc_getClass(className);
|
||||
|
||||
// property_getAttributes() returns everything we need to implement this...
|
||||
// See: http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5
|
||||
objc_property_t prop = class_getProperty(managedObjectClass, propertyName);
|
||||
NSString *attributeString = [NSString stringWithCString:property_getAttributes(prop) encoding:NSUTF8StringEncoding];
|
||||
const char *destinationClassName = [[RKPropertyInspector propertyTypeFromAttributeString:attributeString] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
Class destinationClass = objc_getClass(destinationClassName);
|
||||
|
||||
const char *attr = property_getAttributes(prop);
|
||||
Class destinationClass = [RKPropertyInspector kvcClassFromPropertyAttributes:attr];
|
||||
if (destinationClass) {
|
||||
[propertyNamesAndTypes setObject:destinationClass forKey:name];
|
||||
}
|
||||
|
||||
@@ -74,4 +74,23 @@
|
||||
*/
|
||||
+ (NSString *)propertyTypeFromAttributeString:(NSString *)attributeString;
|
||||
|
||||
/**
|
||||
Returns an appropriate class to use for KVC access based on the Objective C runtime type encoding.
|
||||
|
||||
Objective C Runtime type encodings: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
|
||||
KVC Scalar/Structure support: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/DataTypes.html#//apple_ref/doc/uid/20002171-BAJEAIEE
|
||||
|
||||
@param type An Objective C Runtime type encoding
|
||||
@return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible.
|
||||
*/
|
||||
+ (Class)kvcClassForObjCType:(const char *)type;
|
||||
|
||||
/**
|
||||
Returns an appropriate class to use for KVC access based on the output obtained via the `property_getAttributes` reflection API.
|
||||
|
||||
@param attributeString A c string containing encoding attribute information.
|
||||
@return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible.
|
||||
*/
|
||||
+ (Class)kvcClassFromPropertyAttributes:(const char *)attr;
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "RKPropertyInspector.h"
|
||||
#import "RKLog.h"
|
||||
|
||||
@@ -66,6 +66,77 @@
|
||||
return type;
|
||||
}
|
||||
|
||||
+ (Class)kvcClassForObjCType:(const char *)type
|
||||
{
|
||||
if (type) {
|
||||
// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
|
||||
switch (type[0]) {
|
||||
case '@': {
|
||||
char *openingQuoteLoc = strchr(type, '"');
|
||||
if (openingQuoteLoc) {
|
||||
char *closingQuoteLoc = strchr(openingQuoteLoc+1, '"');
|
||||
if (closingQuoteLoc) {
|
||||
size_t classNameStrLen = closingQuoteLoc-openingQuoteLoc;
|
||||
char className[classNameStrLen];
|
||||
memcpy(className, openingQuoteLoc+1, classNameStrLen-1);
|
||||
// Null-terminate the array to stringify
|
||||
className[classNameStrLen-1] = '\0';
|
||||
return objc_getClass(className);
|
||||
}
|
||||
}
|
||||
// If there is no quoted class type (id), it can be used as-is.
|
||||
return Nil;
|
||||
}
|
||||
|
||||
case 'c': // char
|
||||
case 'C': // unsigned char
|
||||
case 's': // short
|
||||
case 'S': // unsigned short
|
||||
case 'i': // int
|
||||
case 'I': // unsigned int
|
||||
case 'l': // long
|
||||
case 'L': // unsigned long
|
||||
case 'q': // long long
|
||||
case 'Q': // unsigned long long
|
||||
case 'f': // float
|
||||
case 'd': // double
|
||||
return [NSNumber class];
|
||||
|
||||
case 'B': // C++ bool or C99 _Bool
|
||||
return objc_getClass("NSCFBoolean")
|
||||
?: objc_getClass("__NSCFBoolean")
|
||||
?: [NSNumber class];
|
||||
|
||||
case '{': // struct
|
||||
case 'b': // bitfield
|
||||
case '(': // union
|
||||
return [NSValue class];
|
||||
|
||||
case '[': // c array
|
||||
case '^': // pointer
|
||||
case 'v': // void
|
||||
case '*': // char *
|
||||
case '#': // Class
|
||||
case ':': // selector
|
||||
case '?': // unknown type (function pointer, etc)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Nil;
|
||||
}
|
||||
|
||||
+ (Class)kvcClassFromPropertyAttributes:(const char *)attr
|
||||
{
|
||||
if (attr) {
|
||||
const char *typeIdentifierLoc = strchr(attr, 'T');
|
||||
if (typeIdentifierLoc) {
|
||||
return [self kvcClassForObjCType:(typeIdentifierLoc+1)];
|
||||
}
|
||||
}
|
||||
return Nil;
|
||||
}
|
||||
|
||||
- (NSDictionary *)propertyNamesAndTypesForClass:(Class)theClass
|
||||
{
|
||||
NSMutableDictionary *propertyNames = [_propertyNamesToTypesCache objectForKey:theClass];
|
||||
@@ -78,24 +149,24 @@
|
||||
Class currentClass = theClass;
|
||||
while (currentClass != nil) {
|
||||
// Get the raw list of properties
|
||||
unsigned int outCount;
|
||||
unsigned int outCount = 0;
|
||||
objc_property_t *propList = class_copyPropertyList(currentClass, &outCount);
|
||||
|
||||
// Collect the property names
|
||||
int i;
|
||||
NSString *propName;
|
||||
for (i = 0; i < outCount; i++) {
|
||||
// property_getAttributes() returns everything we need to implement this...
|
||||
// See: http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW5
|
||||
for (typeof(outCount) i = 0; i < outCount; i++) {
|
||||
objc_property_t *prop = propList + i;
|
||||
NSString *attributeString = [NSString stringWithCString:property_getAttributes(*prop) encoding:NSUTF8StringEncoding];
|
||||
propName = [NSString stringWithCString:property_getName(*prop) encoding:NSUTF8StringEncoding];
|
||||
const char *propName = property_getName(*prop);
|
||||
|
||||
if (![propName isEqualToString:@"_mapkit_hasPanoramaID"]) {
|
||||
const char *className = [[RKPropertyInspector propertyTypeFromAttributeString:attributeString] cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
Class aClass = objc_getClass(className);
|
||||
if (aClass) {
|
||||
[propertyNames setObject:aClass forKey:propName];
|
||||
if (strcmp(propName, "_mapkit_hasPanoramaID") != 0) {
|
||||
const char *attr = property_getAttributes(*prop);
|
||||
if (attr) {
|
||||
Class aClass = [RKPropertyInspector kvcClassFromPropertyAttributes:attr];
|
||||
if (aClass) {
|
||||
NSString *propNameObj = [[NSString alloc] initWithCString:propName encoding:NSUTF8StringEncoding];
|
||||
if (propNameObj) {
|
||||
[propertyNames setObject:aClass forKey:propNameObj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user