Compare commits
No commits in common. "signal-master" and "master" have entirely different histories.
signal-mas
...
master
@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "Mantle",
|
||||
"version": "2.1.0",
|
||||
"summary": "Model framework for Cocoa and Cocoa Touch.",
|
||||
"homepage": "https://github.com/Mantle/Mantle",
|
||||
"license": "MIT",
|
||||
"authors": {
|
||||
"Github": "support@github.com"
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/github/Mantle.git",
|
||||
"tag": "2.1.0"
|
||||
},
|
||||
"platforms": {
|
||||
"ios": "5.0",
|
||||
"osx": "10.7",
|
||||
"watchos": "2.0",
|
||||
"tvos": "9.0"
|
||||
},
|
||||
"requires_arc": true,
|
||||
"frameworks": "Foundation",
|
||||
"source_files": "Mantle",
|
||||
"subspecs": [
|
||||
{
|
||||
"name": "extobjc",
|
||||
"source_files": "Mantle/extobjc",
|
||||
"private_header_files": "Mantle/extobjc/*.h"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -359,18 +359,7 @@ NSString * const MTLJSONAdapterThrownExceptionErrorKey = @"MTLJSONAdapterThrownE
|
||||
|
||||
id model = [self.modelClass modelWithDictionary:dictionaryValue error:error];
|
||||
|
||||
// BEGIN ORM-PERF-2
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// The validation NSCoding validation reflection used by Mantle is expensive, and
|
||||
// we've never used it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
// return [model validate:error] ? model : nil;
|
||||
//
|
||||
return model;
|
||||
// END ORM-PERF-2
|
||||
return [model validate:error] ? model : nil;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)valueTransformersForModelClass:(Class)modelClass {
|
||||
|
||||
@ -17,15 +17,6 @@ static NSString * const MTLModelVersionKey = @"MTLModelVersion";
|
||||
// Used to cache the reflection performed in +allowedSecureCodingClassesByPropertyKey.
|
||||
static void *MTLModelCachedAllowedClassesKey = &MTLModelCachedAllowedClassesKey;
|
||||
|
||||
// BEGIN ORM-PERF-3
|
||||
// Added by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
|
||||
// to cache the computed reflection on the class via an associated object
|
||||
// Used to cache the reflection performed in +encodingBehaviorsByPropertyKey.
|
||||
static void *MTLModelCachedEncodingBehaviorsByPropertyKeyKey = &MTLModelCachedEncodingBehaviorsByPropertyKeyKey;
|
||||
// END ORM-PERF-3
|
||||
|
||||
// Returns whether the given NSCoder requires secure coding.
|
||||
static BOOL coderRequiresSecureCoding(NSCoder *coder) {
|
||||
SEL requiresSecureCodingSelector = @selector(requiresSecureCoding);
|
||||
@ -72,15 +63,6 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
|
||||
#pragma mark Encoding Behaviors
|
||||
|
||||
+ (NSDictionary *)encodingBehaviorsByPropertyKey {
|
||||
// BEGIN ORM-PERF-3
|
||||
// Added by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
|
||||
// to cache the computed reflection on the class via an associated object
|
||||
NSDictionary *cachedBehaviors = objc_getAssociatedObject(self, MTLModelCachedEncodingBehaviorsByPropertyKeyKey);
|
||||
if (cachedBehaviors != nil) return cachedBehaviors;
|
||||
// END ORM-PERF-3
|
||||
|
||||
NSSet *propertyKeys = self.propertyKeys;
|
||||
NSMutableDictionary *behaviors = [[NSMutableDictionary alloc] initWithCapacity:propertyKeys.count];
|
||||
|
||||
@ -97,14 +79,6 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
|
||||
behaviors[key] = @(behavior);
|
||||
}
|
||||
|
||||
// BEGIN ORM-PERF-3
|
||||
// Added by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
|
||||
// to cache the computed reflection on the class via an associated object
|
||||
objc_setAssociatedObject(self, MTLModelCachedEncodingBehaviorsByPropertyKeyKey, behaviors, OBJC_ASSOCIATION_COPY);
|
||||
// END ORM-PERF-3
|
||||
|
||||
return behaviors;
|
||||
}
|
||||
|
||||
@ -152,21 +126,14 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
|
||||
NSParameterAssert(key != nil);
|
||||
NSParameterAssert(coder != nil);
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
// SEL selector = MTLSelectorWithCapitalizedKeyPattern("decode", key, "WithCoder:modelVersion:");
|
||||
// if ([self respondsToSelector:selector]) {
|
||||
// IMP imp = [self methodForSelector:selector];
|
||||
// id (*function)(id, SEL, NSCoder *, NSUInteger) = (__typeof__(function))imp;
|
||||
// id result = function(self, selector, coder, modelVersion);
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
// END ORM-PERF-1
|
||||
SEL selector = MTLSelectorWithCapitalizedKeyPattern("decode", key, "WithCoder:modelVersion:");
|
||||
if ([self respondsToSelector:selector]) {
|
||||
IMP imp = [self methodForSelector:selector];
|
||||
id (*function)(id, SEL, NSCoder *, NSUInteger) = (__typeof__(function))imp;
|
||||
id result = function(self, selector, coder, modelVersion);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@try {
|
||||
if (coderRequiresSecureCoding(coder)) {
|
||||
|
||||
@ -48,7 +48,7 @@ typedef enum : NSUInteger {
|
||||
/// (like a KVC validation error).
|
||||
///
|
||||
/// Returns an initialized model object, or nil if validation failed.
|
||||
+ (instancetype)modelWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
|
||||
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
|
||||
|
||||
/// A dictionary representing the properties of the receiver.
|
||||
///
|
||||
@ -56,7 +56,7 @@ typedef enum : NSUInteger {
|
||||
/// with any nil values represented by NSNull.
|
||||
///
|
||||
/// This property must never be nil.
|
||||
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *dictionaryValue;
|
||||
@property (nonatomic, copy, readonly) NSDictionary *dictionaryValue;
|
||||
|
||||
/// Initializes the receiver using key-value coding, setting the keys and values
|
||||
/// in the given dictionary.
|
||||
@ -74,22 +74,15 @@ typedef enum : NSUInteger {
|
||||
/// (like a KVC validation error).
|
||||
///
|
||||
/// Returns an initialized model object, or nil if validation failed.
|
||||
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
/// Merges the value of the given key on the receiver with the value of the same
|
||||
/// key from the given model object, giving precedence to the other model object.
|
||||
//- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
|
||||
// END ORM-PERF-1
|
||||
- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
|
||||
|
||||
/// Returns the keys for all @property declarations, except for `readonly`
|
||||
/// properties without ivars, or properties on MTLModel itself.
|
||||
+ (NSSet<NSString *> *)propertyKeys;
|
||||
+ (NSSet *)propertyKeys;
|
||||
|
||||
/// Validates the model.
|
||||
///
|
||||
@ -97,7 +90,7 @@ typedef enum : NSUInteger {
|
||||
/// validation
|
||||
///
|
||||
/// Returns YES if the model is valid, or NO if the validation failed.
|
||||
//- (BOOL)validate:(NSError **)error;
|
||||
- (BOOL)validate:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@ -120,31 +113,23 @@ typedef enum : NSUInteger {
|
||||
/// (like a KVC validation error).
|
||||
///
|
||||
/// Returns an initialized model object, or nil if validation failed.
|
||||
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
|
||||
|
||||
/// Initializes the receiver with default values.
|
||||
///
|
||||
/// This is the designated initializer for this class.
|
||||
- (instancetype)init;
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
/// By default, this method looks for a `-merge<Key>FromModel:` method on the
|
||||
/// receiver, and invokes it if found. If not found, and `model` is not nil, the
|
||||
/// value for the given key is taken from `model`.
|
||||
//- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
|
||||
//
|
||||
- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
|
||||
|
||||
/// Merges the values of the given model object into the receiver, using
|
||||
/// -mergeValueForKey:fromModel: for each key in +propertyKeys.
|
||||
///
|
||||
/// `model` must be an instance of the receiver's class or a subclass thereof.
|
||||
//- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model;
|
||||
//
|
||||
// END ORM-PERF-1
|
||||
- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model;
|
||||
|
||||
/// The storage behavior of a given key.
|
||||
///
|
||||
@ -176,29 +161,19 @@ typedef enum : NSUInteger {
|
||||
|
||||
@end
|
||||
|
||||
// BEGIN ORM-PERF-2
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// The validation NSCoding validation reflection used by Mantle is expensive, and
|
||||
// we've never used it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
///// Implements validation logic for MTLModel.
|
||||
//@interface MTLModel (Validation)
|
||||
//
|
||||
///// Validates the model.
|
||||
/////
|
||||
///// The default implementation simply invokes -validateValue:forKey:error: with
|
||||
///// all +propertyKeys and their current value. If -validateValue:forKey:error:
|
||||
///// returns a new value, the property is set to that new value.
|
||||
/////
|
||||
///// error - If not NULL, this may be set to any error that occurs during
|
||||
///// validation
|
||||
/////
|
||||
///// Returns YES if the model is valid, or NO if the validation failed.
|
||||
//- (BOOL)validate:(NSError **)error;
|
||||
//
|
||||
//@end
|
||||
//
|
||||
// END ORM-PERF-2
|
||||
/// Implements validation logic for MTLModel.
|
||||
@interface MTLModel (Validation)
|
||||
|
||||
/// Validates the model.
|
||||
///
|
||||
/// The default implementation simply invokes -validateValue:forKey:error: with
|
||||
/// all +propertyKeys and their current value. If -validateValue:forKey:error:
|
||||
/// returns a new value, the property is set to that new value.
|
||||
///
|
||||
/// error - If not NULL, this may be set to any error that occurs during
|
||||
/// validation
|
||||
///
|
||||
/// Returns YES if the model is valid, or NO if the validation failed.
|
||||
- (BOOL)validate:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
@ -24,24 +24,6 @@ static void *MTLModelCachedTransitoryPropertyKeysKey = &MTLModelCachedTransitory
|
||||
// property keys.
|
||||
static void *MTLModelCachedPermanentPropertyKeysKey = &MTLModelCachedPermanentPropertyKeysKey;
|
||||
|
||||
// BEGIN ORM-PERF-4
|
||||
// Added by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// +dictionaryValueKeys is somewhat expensive, so we follow existing library patterns
|
||||
// to cache the computed reflection on the class via an associated object
|
||||
//
|
||||
// Used to cache the reflection performed in +dictionaryValueKeys
|
||||
static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryValueKeysKey;
|
||||
// END ORM-PERF-4
|
||||
|
||||
// BEGIN ORM-PERF-2
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// The validation NSCoding validation reflection used by Mantle is expensive, and
|
||||
// we've never used it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
// Validates a value for an object and sets it if necessary.
|
||||
//
|
||||
// obj - The object for which the value is being validated. This value
|
||||
@ -56,36 +38,35 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
//
|
||||
// Returns YES if `value` could be validated and set, or NO if an error
|
||||
// occurred.
|
||||
//static BOOL MTLValidateAndSetValue(id obj, NSString *key, id value, BOOL forceUpdate, NSError **error) {
|
||||
// // Mark this as being autoreleased, because validateValue may return
|
||||
// // a new object to be stored in this variable (and we don't want ARC to
|
||||
// // double-free or leak the old or new values).
|
||||
// __autoreleasing id validatedValue = value;
|
||||
//
|
||||
// @try {
|
||||
// if (![obj validateValue:&validatedValue forKey:key error:error]) return NO;
|
||||
//
|
||||
// if (forceUpdate || value != validatedValue) {
|
||||
// [obj setValue:validatedValue forKey:key];
|
||||
// }
|
||||
//
|
||||
// return YES;
|
||||
// } @catch (NSException *ex) {
|
||||
// NSLog(@"*** Caught exception setting key \"%@\" : %@", key, ex);
|
||||
//
|
||||
// // Fail fast in Debug builds.
|
||||
// #if DEBUG
|
||||
// @throw ex;
|
||||
// #else
|
||||
// if (error != NULL) {
|
||||
// *error = [NSError mtl_modelErrorWithException:ex];
|
||||
// }
|
||||
//
|
||||
// return NO;
|
||||
// #endif
|
||||
// }
|
||||
//}
|
||||
// END ORM-PERF-2
|
||||
static BOOL MTLValidateAndSetValue(id obj, NSString *key, id value, BOOL forceUpdate, NSError **error) {
|
||||
// Mark this as being autoreleased, because validateValue may return
|
||||
// a new object to be stored in this variable (and we don't want ARC to
|
||||
// double-free or leak the old or new values).
|
||||
__autoreleasing id validatedValue = value;
|
||||
|
||||
@try {
|
||||
if (![obj validateValue:&validatedValue forKey:key error:error]) return NO;
|
||||
|
||||
if (forceUpdate || value != validatedValue) {
|
||||
[obj setValue:validatedValue forKey:key];
|
||||
}
|
||||
|
||||
return YES;
|
||||
} @catch (NSException *ex) {
|
||||
NSLog(@"*** Caught exception setting key \"%@\" : %@", key, ex);
|
||||
|
||||
// Fail fast in Debug builds.
|
||||
#if DEBUG
|
||||
@throw ex;
|
||||
#else
|
||||
if (error != NULL) {
|
||||
*error = [NSError mtl_modelErrorWithException:ex];
|
||||
}
|
||||
|
||||
return NO;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@interface MTLModel ()
|
||||
|
||||
@ -95,11 +76,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
|
||||
// Returns a set of all property keys for which
|
||||
// +storageBehaviorForPropertyWithKey returned MTLPropertyStorageTransitory.
|
||||
+ (NSSet<NSString *> *)transitoryPropertyKeys;
|
||||
+ (NSSet *)transitoryPropertyKeys;
|
||||
|
||||
// Returns a set of all property keys for which
|
||||
// +storageBehaviorForPropertyWithKey returned MTLPropertyStoragePermanent.
|
||||
+ (NSSet<NSString *> *)permanentPropertyKeys;
|
||||
+ (NSSet *)permanentPropertyKeys;
|
||||
|
||||
// Enumerates all properties of the receiver's class hierarchy, starting at the
|
||||
// receiver, and continuing up until (but not including) MTLModel.
|
||||
@ -115,8 +96,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
#pragma mark Lifecycle
|
||||
|
||||
+ (void)generateAndCacheStorageBehaviors {
|
||||
NSMutableSet<NSString *> *transitoryKeys = [NSMutableSet set];
|
||||
NSMutableSet<NSString *> *permanentKeys = [NSMutableSet set];
|
||||
NSMutableSet *transitoryKeys = [NSMutableSet set];
|
||||
NSMutableSet *permanentKeys = [NSMutableSet set];
|
||||
|
||||
for (NSString *propertyKey in self.propertyKeys) {
|
||||
switch ([self storageBehaviorForPropertyWithKey:propertyKey]) {
|
||||
@ -139,7 +120,7 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
objc_setAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey, permanentKeys, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
+ (instancetype)modelWithDictionary:(NSDictionary<NSString *, id> *)dictionary error:(NSError **)error {
|
||||
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
|
||||
return [[self alloc] initWithDictionary:dictionary error:error];
|
||||
}
|
||||
|
||||
@ -148,7 +129,7 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionary error:(NSError **)error {
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
|
||||
self = [self init];
|
||||
if (self == nil) return nil;
|
||||
|
||||
@ -159,18 +140,9 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
__autoreleasing id value = [dictionary objectForKey:key];
|
||||
|
||||
if ([value isEqual:NSNull.null]) value = nil;
|
||||
// BEGIN ORM-PERF-2
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// The validation NSCoding validation reflection used by Mantle is expensive, and
|
||||
// we've never used it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
// BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
|
||||
// if (!success) return nil;
|
||||
[self setValue:value forKey:key];
|
||||
// END ORM-PERF-2
|
||||
|
||||
BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
|
||||
if (!success) return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
@ -200,11 +172,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)propertyKeys {
|
||||
NSSet<NSString *> *cachedKeys = objc_getAssociatedObject(self, MTLModelCachedPropertyKeysKey);
|
||||
+ (NSSet *)propertyKeys {
|
||||
NSSet *cachedKeys = objc_getAssociatedObject(self, MTLModelCachedPropertyKeysKey);
|
||||
if (cachedKeys != nil) return cachedKeys;
|
||||
|
||||
NSMutableSet<NSString *> *keys = [NSMutableSet set];
|
||||
NSMutableSet *keys = [NSMutableSet set];
|
||||
|
||||
[self enumeratePropertiesUsingBlock:^(objc_property_t property, BOOL *stop) {
|
||||
NSString *key = @(property_getName(property));
|
||||
@ -221,8 +193,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
return keys;
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)transitoryPropertyKeys {
|
||||
NSSet<NSString *> *transitoryPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedTransitoryPropertyKeysKey);
|
||||
+ (NSSet *)transitoryPropertyKeys {
|
||||
NSSet *transitoryPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedTransitoryPropertyKeysKey);
|
||||
|
||||
if (transitoryPropertyKeys == nil) {
|
||||
[self generateAndCacheStorageBehaviors];
|
||||
@ -232,8 +204,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
return transitoryPropertyKeys;
|
||||
}
|
||||
|
||||
+ (NSSet<NSString *> *)permanentPropertyKeys {
|
||||
NSSet<NSString *> *permanentPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey);
|
||||
+ (NSSet *)permanentPropertyKeys {
|
||||
NSSet *permanentPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey);
|
||||
|
||||
if (permanentPropertyKeys == nil) {
|
||||
[self generateAndCacheStorageBehaviors];
|
||||
@ -243,28 +215,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
return permanentPropertyKeys;
|
||||
}
|
||||
|
||||
// BEGIN ORM-PERF-4
|
||||
// Added by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// +dictionaryValueKeys is somewhat expensive, so we follow existing library patterns
|
||||
// to cache the computed reflection on the class via an associated object
|
||||
//
|
||||
// Used to cache the reflection performed in +dictionaryValueKeys
|
||||
+ (NSArray<NSString *> *)dictionaryValueKeys {
|
||||
NSArray<NSString *> *dictionaryValueKeys = objc_getAssociatedObject(self, MTLModelCachedDictionaryValueKeysKey);
|
||||
if (!dictionaryValueKeys) {
|
||||
NSSet<NSString *> *keys = [self.class.transitoryPropertyKeys setByAddingObjectsFromSet:self.permanentPropertyKeys];
|
||||
dictionaryValueKeys = keys.allObjects;
|
||||
objc_setAssociatedObject(self, MTLModelCachedDictionaryValueKeysKey, dictionaryValueKeys, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
return dictionaryValueKeys;
|
||||
}
|
||||
- (NSDictionary *)dictionaryValue {
|
||||
NSSet *keys = [self.class.transitoryPropertyKeys setByAddingObjectsFromSet:self.class.permanentPropertyKeys];
|
||||
|
||||
- (NSDictionary<NSString *, id> *)dictionaryValue {
|
||||
NSArray<NSString *> *keys = self.class.dictionaryValueKeys;
|
||||
return [self dictionaryWithValuesForKeys:keys];
|
||||
return [self dictionaryWithValuesForKeys:keys.allObjects];
|
||||
}
|
||||
// END ORM-PERF-4
|
||||
|
||||
+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey {
|
||||
objc_property_t property = class_getProperty(self.class, propertyKey.UTF8String);
|
||||
@ -295,61 +250,45 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
|
||||
#pragma mark Merging
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
//- (void)mergeValueForKey:(NSString *)key fromModel:(NSObject<MTLModel> *)model {
|
||||
// NSParameterAssert(key != nil);
|
||||
//
|
||||
//// SEL selector = MTLSelectorWithCapitalizedKeyPattern("merge", key, "FromModel:");
|
||||
//// if (![self respondsToSelector:selector]) {
|
||||
//// if (model != nil) {
|
||||
//// [self setValue:[model valueForKey:key] forKey:key];
|
||||
//// }
|
||||
////
|
||||
//// return;
|
||||
//// }
|
||||
//
|
||||
// IMP imp = [self methodForSelector:selector];
|
||||
// void (*function)(id, SEL, id<MTLModel>) = (__typeof__(function))imp;
|
||||
// function(self, selector, model);
|
||||
//}
|
||||
//
|
||||
//- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model {
|
||||
// NSSet<NSString *> *propertyKeys = model.class.propertyKeys;
|
||||
//
|
||||
// for (NSString *key in self.class.propertyKeys) {
|
||||
// if (![propertyKeys containsObject:key]) continue;
|
||||
//
|
||||
// [self mergeValueForKey:key fromModel:model];
|
||||
// }
|
||||
//}
|
||||
// END ORM-PERF-1
|
||||
- (void)mergeValueForKey:(NSString *)key fromModel:(NSObject<MTLModel> *)model {
|
||||
NSParameterAssert(key != nil);
|
||||
|
||||
// BEGIN ORM-PERF-2
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
//
|
||||
// The validation NSCoding validation reflection used by Mantle is expensive, and
|
||||
// we've never used it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//#pragma mark Validation
|
||||
//
|
||||
//- (BOOL)validate:(NSError **)error {
|
||||
// for (NSString *key in self.class.propertyKeys) {
|
||||
// id value = [self valueForKey:key];
|
||||
//
|
||||
// BOOL success = MTLValidateAndSetValue(self, key, value, NO, error);
|
||||
// if (!success) return NO;
|
||||
// }
|
||||
//
|
||||
// return YES;
|
||||
//}
|
||||
// END ORM-PERF-2
|
||||
SEL selector = MTLSelectorWithCapitalizedKeyPattern("merge", key, "FromModel:");
|
||||
if (![self respondsToSelector:selector]) {
|
||||
if (model != nil) {
|
||||
[self setValue:[model valueForKey:key] forKey:key];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IMP imp = [self methodForSelector:selector];
|
||||
void (*function)(id, SEL, id<MTLModel>) = (__typeof__(function))imp;
|
||||
function(self, selector, model);
|
||||
}
|
||||
|
||||
- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model {
|
||||
NSSet *propertyKeys = model.class.propertyKeys;
|
||||
|
||||
for (NSString *key in self.class.propertyKeys) {
|
||||
if (![propertyKeys containsObject:key]) continue;
|
||||
|
||||
[self mergeValueForKey:key fromModel:model];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Validation
|
||||
|
||||
- (BOOL)validate:(NSError **)error {
|
||||
for (NSString *key in self.class.propertyKeys) {
|
||||
id value = [self valueForKey:key];
|
||||
|
||||
BOOL success = MTLValidateAndSetValue(self, key, value, NO, error);
|
||||
if (!success) return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
@ -362,13 +301,9 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
|
||||
#pragma mark NSObject
|
||||
|
||||
- (NSString *)description {
|
||||
#if DEBUG
|
||||
NSDictionary<NSString *, id> *permanentProperties = [self dictionaryWithValuesForKeys:self.class.permanentPropertyKeys.allObjects];
|
||||
NSDictionary *permanentProperties = [self dictionaryWithValuesForKeys:self.class.permanentPropertyKeys.allObjects];
|
||||
|
||||
return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, permanentProperties];
|
||||
#else
|
||||
return [NSString stringWithFormat:@"<%@: %p>", self.class, self];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
|
||||
@ -18,14 +18,6 @@
|
||||
/// selector.
|
||||
SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2)));
|
||||
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//
|
||||
/// Creates a selector from a key and a constant prefix and suffix.
|
||||
///
|
||||
/// prefix - A string to prepend to the key as part of the selector.
|
||||
@ -36,6 +28,4 @@ SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) __attribute__((
|
||||
///
|
||||
/// Returns a selector, or NULL if the input strings cannot form a valid
|
||||
/// selector.
|
||||
//SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2, 3)));
|
||||
//
|
||||
// END ORM-PERF-1
|
||||
SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2, 3)));
|
||||
|
||||
@ -24,34 +24,27 @@ SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) {
|
||||
return sel_registerName(selector);
|
||||
}
|
||||
|
||||
// BEGIN ORM-PERF-1
|
||||
// Commented out by mkirk as part of ORM perf optimizations.
|
||||
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
|
||||
// and we're not using the reflective features that require it.
|
||||
// If we later want to use this feature, we'll need to carefully evaluate the perf
|
||||
// implications on large migrations.
|
||||
//SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) {
|
||||
// NSUInteger prefixLength = strlen(prefix);
|
||||
// NSUInteger suffixLength = strlen(suffix);
|
||||
//
|
||||
// NSString *initial = [key substringToIndex:1].uppercaseString;
|
||||
// NSUInteger initialLength = [initial maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
//
|
||||
// NSString *rest = [key substringFromIndex:1];
|
||||
// NSUInteger restLength = [rest maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
//
|
||||
// char selector[prefixLength + initialLength + restLength + suffixLength + 1];
|
||||
// memcpy(selector, prefix, prefixLength);
|
||||
//
|
||||
// BOOL success = [initial getBytes:selector + prefixLength maxLength:initialLength usedLength:&initialLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, initial.length) remainingRange:NULL];
|
||||
// if (!success) return NULL;
|
||||
//
|
||||
// success = [rest getBytes:selector + prefixLength + initialLength maxLength:restLength usedLength:&restLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, rest.length) remainingRange:NULL];
|
||||
// if (!success) return NULL;
|
||||
//
|
||||
// memcpy(selector + prefixLength + initialLength + restLength, suffix, suffixLength);
|
||||
// selector[prefixLength + initialLength + restLength + suffixLength] = '\0';
|
||||
//
|
||||
// return sel_registerName(selector);
|
||||
//}
|
||||
// END ORM-PERF-1
|
||||
SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) {
|
||||
NSUInteger prefixLength = strlen(prefix);
|
||||
NSUInteger suffixLength = strlen(suffix);
|
||||
|
||||
NSString *initial = [key substringToIndex:1].uppercaseString;
|
||||
NSUInteger initialLength = [initial maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
NSString *rest = [key substringFromIndex:1];
|
||||
NSUInteger restLength = [rest maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
char selector[prefixLength + initialLength + restLength + suffixLength + 1];
|
||||
memcpy(selector, prefix, prefixLength);
|
||||
|
||||
BOOL success = [initial getBytes:selector + prefixLength maxLength:initialLength usedLength:&initialLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, initial.length) remainingRange:NULL];
|
||||
if (!success) return NULL;
|
||||
|
||||
success = [rest getBytes:selector + prefixLength + initialLength maxLength:restLength usedLength:&restLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, rest.length) remainingRange:NULL];
|
||||
if (!success) return NULL;
|
||||
|
||||
memcpy(selector + prefixLength + initialLength + restLength, suffix, suffixLength);
|
||||
selector[prefixLength + initialLength + restLength + suffixLength] = '\0';
|
||||
|
||||
return sel_registerName(selector);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user