mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 20:31:13 +08:00
Merge branch 'development' of github.com:CFKevinRef/RestKit into CFKevinRef-development
This commit is contained in:
@@ -94,7 +94,7 @@
|
||||
return NO;
|
||||
}
|
||||
|
||||
Class attributeType = [[RKPropertyInspector sharedInspector] typeForProperty:self.attribute ofEntity:self.entity];
|
||||
Class attributeType = [[RKPropertyInspector sharedInspector] classForPropertyNamed:self.attribute ofEntity:self.entity];
|
||||
return [attributeType instancesRespondToSelector:@selector(stringValue)];
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
{
|
||||
Class propertyClass = [super classForProperty:propertyName];
|
||||
if (! propertyClass) {
|
||||
propertyClass = [[RKPropertyInspector sharedInspector] typeForProperty:propertyName ofEntity:self.entity];
|
||||
propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:propertyName ofEntity:self.entity];
|
||||
}
|
||||
|
||||
return propertyClass;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
NSAssert(managedObjectContext, @"Cannot find existing managed object with a nil context");
|
||||
|
||||
id searchValue = primaryKeyValue;
|
||||
Class type = [[RKPropertyInspector sharedInspector] typeForProperty:primaryKeyAttribute ofEntity:entity];
|
||||
Class type = [[RKPropertyInspector sharedInspector] classForPropertyNamed:primaryKeyAttribute ofEntity:entity];
|
||||
if (type && ([type isSubclassOfClass:[NSString class]] && NO == [primaryKeyValue isKindOfClass:[NSString class]])) {
|
||||
searchValue = [NSString stringWithFormat:@"%@", primaryKeyValue];
|
||||
} else if (type && ([type isSubclassOfClass:[NSNumber class]] && NO == [primaryKeyValue isKindOfClass:[NSNumber class]])) {
|
||||
|
||||
@@ -20,13 +20,26 @@
|
||||
|
||||
#import "RKPropertyInspector.h"
|
||||
|
||||
/**
|
||||
The `CoreData` category augments the `RKPropertyInspector` class with support for introspecting the property types for `NSManagedObject` and `NSEntityDescription` objects.
|
||||
*/
|
||||
@interface RKPropertyInspector (CoreData)
|
||||
|
||||
- (NSDictionary *)propertyNamesAndTypesForEntity:(NSEntityDescription *)entity;
|
||||
/**
|
||||
Returns a dictionary wherein the keys are the names of attribute and relationship properties and the values are the class used to represent the corresponding property for a given entity.
|
||||
|
||||
@param entity The entity to retrieve the properties names and classes of.
|
||||
@return A dictionary containing the names and classes of the given entity.
|
||||
*/
|
||||
- (NSDictionary *)propertyNamesAndClassesForEntity:(NSEntityDescription *)entity;
|
||||
|
||||
/**
|
||||
Returns the Class type of the specified property on the object class
|
||||
Returns the class used to represent the property with the given name on the given entity.
|
||||
|
||||
@param propertyName The name of the property to retrieve the class for.
|
||||
@param entity The entity containing the property to retrieve the class for.
|
||||
@return The class used to represent the property.
|
||||
*/
|
||||
- (Class)typeForProperty:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity;
|
||||
- (Class)classForPropertyNamed:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity;
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
//
|
||||
|
||||
#import <CoreData/CoreData.h>
|
||||
#import <objc/message.h>
|
||||
#import "RKPropertyInspector+CoreData.h"
|
||||
#import "RKLog.h"
|
||||
#import "RKObjectUtilities.h"
|
||||
#import "RKMacros.h"
|
||||
#import <objc/message.h>
|
||||
|
||||
|
||||
RK_FIX_CATEGORY_BUG(RKPropertyInspector_CoreData)
|
||||
|
||||
@@ -33,7 +33,7 @@ RK_FIX_CATEGORY_BUG(RKPropertyInspector_CoreData)
|
||||
|
||||
@implementation RKPropertyInspector (CoreData)
|
||||
|
||||
- (NSDictionary *)propertyNamesAndTypesForEntity:(NSEntityDescription *)entity
|
||||
- (NSDictionary *)propertyNamesAndClassesForEntity:(NSEntityDescription *)entity
|
||||
{
|
||||
NSMutableDictionary *propertyNamesAndTypes = [_propertyNamesToTypesCache objectForKey:[entity name]];
|
||||
if (propertyNamesAndTypes) {
|
||||
@@ -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 = RKKeyValueCodingClassFromPropertyAttributes(attr);
|
||||
if (destinationClass) {
|
||||
[propertyNamesAndTypes setObject:destinationClass forKey:name];
|
||||
}
|
||||
@@ -81,9 +83,9 @@ RK_FIX_CATEGORY_BUG(RKPropertyInspector_CoreData)
|
||||
return propertyNamesAndTypes;
|
||||
}
|
||||
|
||||
- (Class)typeForProperty:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity
|
||||
- (Class)classForPropertyNamed:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity
|
||||
{
|
||||
return [[self propertyNamesAndTypesForEntity:entity] valueForKey:propertyName];
|
||||
return [[self propertyNamesAndClassesForEntity:entity] valueForKey:propertyName];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -294,7 +294,7 @@ NSDate *RKDateFromStringWithFormatters(NSString *dateString, NSArray *formatters
|
||||
|
||||
- (Class)classForProperty:(NSString *)propertyName
|
||||
{
|
||||
return [[RKPropertyInspector sharedInspector] typeForProperty:propertyName ofClass:self.objectClass];
|
||||
return [[RKPropertyInspector sharedInspector] classForPropertyNamed:propertyName ofClass:self.objectClass];
|
||||
}
|
||||
|
||||
- (Class)classForKeyPath:(NSString *)keyPath
|
||||
@@ -302,7 +302,7 @@ NSDate *RKDateFromStringWithFormatters(NSString *dateString, NSArray *formatters
|
||||
NSArray *components = [keyPath componentsSeparatedByString:@"."];
|
||||
Class propertyClass = self.objectClass;
|
||||
for (NSString *property in components) {
|
||||
propertyClass = [[RKPropertyInspector sharedInspector] typeForProperty:property ofClass:propertyClass];
|
||||
propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofClass:propertyClass];
|
||||
if (! propertyClass) break;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,3 +68,30 @@ BOOL RKObjectIsCollection(id object);
|
||||
@return `YES` if the object is a collection containing only `NSManagedObject` derived objects.
|
||||
*/
|
||||
BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object);
|
||||
|
||||
/**
|
||||
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 RKKeyValueCodingClassForObjCType(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 RKKeyValueCodingClassFromPropertyAttributes(const char *attr);
|
||||
|
||||
/**
|
||||
Returns the name of a property when provided the name of a property obtained via the `property_getAttributes` reflection API.
|
||||
|
||||
@param attributeString A string object encoding attribute information.
|
||||
@return The class name for the property type encoded in the given attribute string or `@"NULL"` if the property does not have an object type (the declared property is for a primitive type).
|
||||
*/
|
||||
NSString *RKPropertyTypeFromAttributeString(NSString *attributeString);
|
||||
|
||||
@@ -71,3 +71,91 @@ BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object)
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
Class RKKeyValueCodingClassForObjCType(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 RKKeyValueCodingClassFromPropertyAttributes(const char *attr)
|
||||
{
|
||||
if (attr) {
|
||||
const char *typeIdentifierLoc = strchr(attr, 'T');
|
||||
if (typeIdentifierLoc) {
|
||||
return RKKeyValueCodingClassForObjCType(typeIdentifierLoc+1);
|
||||
}
|
||||
}
|
||||
return Nil;
|
||||
}
|
||||
|
||||
NSString *RKPropertyTypeFromAttributeString(NSString *attributeString)
|
||||
{
|
||||
NSString *type = [NSString string];
|
||||
NSScanner *typeScanner = [NSScanner scannerWithString:attributeString];
|
||||
[typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"@"] intoString:NULL];
|
||||
|
||||
// we are not dealing with an object
|
||||
if ([typeScanner isAtEnd]) {
|
||||
return @"NULL";
|
||||
}
|
||||
[typeScanner scanCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"@"] intoString:NULL];
|
||||
// this gets the actual object type
|
||||
[typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&type];
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -60,18 +60,6 @@
|
||||
@param objectClass The class to retrieve the property from.
|
||||
@return A `Class` object specifying the type of the requested property.
|
||||
*/
|
||||
- (Class)typeForProperty:(NSString *)propertyName ofClass:(Class)objectClass;
|
||||
|
||||
///------------------------------------------------------
|
||||
/// @name Retrieving the Properties and Types for a Class
|
||||
///------------------------------------------------------
|
||||
|
||||
/**
|
||||
Returns the name of a property when provided the name of a property obtained via the `property_getAttributes` reflection API.
|
||||
|
||||
@param attributeString A string object encoding attribute information.
|
||||
@return The class name for the property type encoded in the given attribute string or `@"NULL"` if the property does not have an object type (the declared property is for a primitive type).
|
||||
*/
|
||||
+ (NSString *)propertyTypeFromAttributeString:(NSString *)attributeString;
|
||||
- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass;
|
||||
|
||||
@end
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <objc/message.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "RKPropertyInspector.h"
|
||||
#import "RKLog.h"
|
||||
#import "RKObjectUtilities.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
@@ -49,23 +50,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+ (NSString *)propertyTypeFromAttributeString:(NSString *)attributeString
|
||||
{
|
||||
NSString *type = [NSString string];
|
||||
NSScanner *typeScanner = [NSScanner scannerWithString:attributeString];
|
||||
[typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"@"] intoString:NULL];
|
||||
|
||||
// we are not dealing with an object
|
||||
if ([typeScanner isAtEnd]) {
|
||||
return @"NULL";
|
||||
}
|
||||
[typeScanner scanCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"@"] intoString:NULL];
|
||||
// this gets the actual object type
|
||||
[typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&type];
|
||||
return type;
|
||||
}
|
||||
|
||||
- (NSDictionary *)propertyNamesAndTypesForClass:(Class)theClass
|
||||
{
|
||||
NSMutableDictionary *propertyNames = [_propertyNamesToTypesCache objectForKey:theClass];
|
||||
@@ -78,24 +62,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 = RKKeyValueCodingClassFromPropertyAttributes(attr);
|
||||
if (aClass) {
|
||||
NSString *propNameObj = [[NSString alloc] initWithCString:propName encoding:NSUTF8StringEncoding];
|
||||
if (propNameObj) {
|
||||
[propertyNames setObject:aClass forKey:propNameObj];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +93,7 @@
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
- (Class)typeForProperty:(NSString *)propertyName ofClass:(Class)objectClass
|
||||
- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass
|
||||
{
|
||||
NSDictionary *dictionary = [self propertyNamesAndTypesForClass:objectClass];
|
||||
return [dictionary objectForKey:propertyName];
|
||||
|
||||
Reference in New Issue
Block a user