X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/Realm/RLMObjectBase.mm diff --git a/iOS/Pods/Realm/Realm/RLMObjectBase.mm b/iOS/Pods/Realm/Realm/RLMObjectBase.mm new file mode 100644 index 0000000..434475f --- /dev/null +++ b/iOS/Pods/Realm/Realm/RLMObjectBase.mm @@ -0,0 +1,538 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2014 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#import "RLMObject_Private.hpp" + +#import "RLMAccessor.h" +#import "RLMArray_Private.hpp" +#import "RLMListBase.h" +#import "RLMObjectSchema_Private.hpp" +#import "RLMObjectStore.h" +#import "RLMObservation.hpp" +#import "RLMOptionalBase.h" +#import "RLMProperty_Private.h" +#import "RLMRealm_Private.hpp" +#import "RLMSchema_Private.h" +#import "RLMSwiftSupport.h" +#import "RLMThreadSafeReference_Private.hpp" +#import "RLMUtil.hpp" + +#import "object.hpp" +#import "shared_realm.hpp" + +using namespace realm; + +const NSUInteger RLMDescriptionMaxDepth = 5; + +static bool maybeInitObjectSchemaForUnmanaged(RLMObjectBase *obj) { + obj->_objectSchema = [obj.class sharedSchema]; + if (!obj->_objectSchema) { + return false; + } + + // set default values + if (!obj->_objectSchema.isSwiftClass) { + NSDictionary *dict = RLMDefaultValuesForObjectSchema(obj->_objectSchema); + for (NSString *key in dict) { + [obj setValue:dict[key] forKey:key]; + } + } + + // set unmanaged accessor class + object_setClass(obj, obj->_objectSchema.unmanagedClass); + return true; +} + +@interface RLMObjectBase () +@end + +@implementation RLMObjectBase +// unmanaged init +- (instancetype)init { + if ((self = [super init])) { + maybeInitObjectSchemaForUnmanaged(self); + } + return self; +} + +- (void)dealloc { + // This can't be a unique_ptr because associated objects are removed + // *after* c++ members are destroyed and dealloc is called, and we need it + // to be in a validish state when that happens + delete _observationInfo; + _observationInfo = nullptr; +} + +static id coerceToObjectType(id obj, Class cls, RLMSchema *schema) { + return [obj isKindOfClass:cls] ? obj : [[cls alloc] initWithValue:obj schema:schema]; +} + +static id validatedObjectForProperty(__unsafe_unretained id const obj, + __unsafe_unretained RLMObjectSchema *const objectSchema, + __unsafe_unretained RLMProperty *const prop, + __unsafe_unretained RLMSchema *const schema) { + RLMValidateValueForProperty(obj, objectSchema, prop); + if (!obj || obj == NSNull.null) { + return nil; + } + if (prop.type == RLMPropertyTypeObject) { + Class objectClass = schema[prop.objectClassName].objectClass; + if (prop.array) { + NSMutableArray *ret = [[NSMutableArray alloc] init]; + for (id el in obj) { + [ret addObject:coerceToObjectType(el, objectClass, schema)]; + } + return ret; + } + return coerceToObjectType(obj, objectClass, schema); + } + return obj; +} + +- (instancetype)initWithValue:(id)value schema:(RLMSchema *)schema { + if (!(self = [super init])) { + return self; + } + + if (!value || value == NSNull.null) { + @throw RLMException(@"Must provide a non-nil value."); + } + + if (!maybeInitObjectSchemaForUnmanaged(self)) { + // Don't populate fields from the passed-in object if we're called + // during schema init + return self; + } + + NSArray *properties = _objectSchema.properties; + if (NSArray *array = RLMDynamicCast(value)) { + if (array.count > properties.count) { + @throw RLMException(@"Invalid array input: more values (%llu) than properties (%llu).", + (unsigned long long)array.count, (unsigned long long)properties.count); + } + NSUInteger i = 0; + for (id val in array) { + RLMProperty *prop = properties[i++]; + [self setValue:validatedObjectForProperty(RLMCoerceToNil(val), _objectSchema, prop, schema) + forKey:prop.name]; + } + } + else { + // assume our object is an NSDictionary or an object with kvc properties + for (RLMProperty *prop in properties) { + id obj = RLMValidatedValueForProperty(value, prop.name, _objectSchema.className); + + // don't set unspecified properties + if (!obj) { + continue; + } + + [self setValue:validatedObjectForProperty(RLMCoerceToNil(obj), _objectSchema, prop, schema) + forKey:prop.name]; + } + } + + return self; +} + +id RLMCreateManagedAccessor(Class cls, __unsafe_unretained RLMRealm *realm, RLMClassInfo *info) { + RLMObjectBase *obj = [[cls alloc] initWithRealm:realm schema:info->rlmObjectSchema]; + obj->_info = info; + return obj; +} + +- (instancetype)initWithRealm:(__unsafe_unretained RLMRealm *const)realm + schema:(RLMObjectSchema *)schema { + self = [super init]; + if (self) { + _realm = realm; + _objectSchema = schema; + } + return self; +} + +- (id)valueForKey:(NSString *)key { + if (_observationInfo) { + return _observationInfo->valueForKey(key); + } + return [super valueForKey:key]; +} + +// Generic Swift properties can't be dynamic, so KVO doesn't work for them by default +- (id)valueForUndefinedKey:(NSString *)key { + if (Ivar ivar = _objectSchema[key].swiftIvar) { + return RLMCoerceToNil(object_getIvar(self, ivar)); + } + return [super valueForUndefinedKey:key]; +} + +- (void)setValue:(id)value forUndefinedKey:(NSString *)key { + value = RLMCoerceToNil(value); + RLMProperty *property = _objectSchema[key]; + if (Ivar ivar = property.swiftIvar) { + if (property.array && (!value || [value conformsToProtocol:@protocol(NSFastEnumeration)])) { + RLMArray *array = [object_getIvar(self, ivar) _rlmArray]; + [array removeAllObjects]; + + if (value) { + [array addObjects:validatedObjectForProperty(value, _objectSchema, property, + RLMSchema.partialPrivateSharedSchema)]; + } + } + else if (property.optional) { + RLMOptionalBase *optional = object_getIvar(self, ivar); + optional.underlyingValue = value; + } + return; + } + [super setValue:value forUndefinedKey:key]; +} + +// overridden at runtime per-class for performance ++ (NSString *)className { + NSString *className = NSStringFromClass(self); + if ([RLMSwiftSupport isSwiftClassName:className]) { + className = [RLMSwiftSupport demangleClassName:className]; + } + return className; +} + +// overridden at runtime per-class for performance ++ (RLMObjectSchema *)sharedSchema { + return [RLMSchema sharedSchemaForClass:self.class]; +} + ++ (void)initializeLinkedObjectSchemas { + for (RLMProperty *prop in self.sharedSchema.properties) { + if (prop.type == RLMPropertyTypeObject && !RLMSchema.partialPrivateSharedSchema[prop.objectClassName]) { + [[RLMSchema classForString:prop.objectClassName] initializeLinkedObjectSchemas]; + } + } +} + ++ (Class)objectUtilClass:(BOOL)isSwift { + return RLMObjectUtilClass(isSwift); +} + +- (NSString *)description +{ + if (self.isInvalidated) { + return @"[invalid object]"; + } + + return [self descriptionWithMaxDepth:RLMDescriptionMaxDepth]; +} + +- (NSString *)descriptionWithMaxDepth:(NSUInteger)depth { + if (depth == 0) { + return @""; + } + + NSString *baseClassName = _objectSchema.className; + NSMutableString *mString = [NSMutableString stringWithFormat:@"%@ {\n", baseClassName]; + + for (RLMProperty *property in _objectSchema.properties) { + id object = RLMObjectBaseObjectForKeyedSubscript(self, property.name); + NSString *sub; + if ([object respondsToSelector:@selector(descriptionWithMaxDepth:)]) { + sub = [object descriptionWithMaxDepth:depth - 1]; + } + else if (property.type == RLMPropertyTypeData) { + static NSUInteger maxPrintedDataLength = 24; + NSData *data = object; + NSUInteger length = data.length; + if (length > maxPrintedDataLength) { + data = [NSData dataWithBytes:data.bytes length:maxPrintedDataLength]; + } + NSString *dataDescription = [data description]; + sub = [NSString stringWithFormat:@"<%@ — %lu total bytes>", [dataDescription substringWithRange:NSMakeRange(1, dataDescription.length - 2)], (unsigned long)length]; + } + else { + sub = [object description]; + } + [mString appendFormat:@"\t%@ = %@;\n", property.name, [sub stringByReplacingOccurrencesOfString:@"\n" withString:@"\n\t"]]; + } + [mString appendString:@"}"]; + + return [NSString stringWithString:mString]; +} + +- (RLMRealm *)realm { + return _realm; +} + +- (RLMObjectSchema *)objectSchema { + return _objectSchema; +} + +- (BOOL)isInvalidated { + // if not unmanaged and our accessor has been detached, we have been deleted + return self.class == _objectSchema.accessorClass && !_row.is_attached(); +} + +- (BOOL)isEqual:(id)object { + if (RLMObjectBase *other = RLMDynamicCast(object)) { + if (_objectSchema.primaryKeyProperty) { + return RLMObjectBaseAreEqual(self, other); + } + } + return [super isEqual:object]; +} + +- (NSUInteger)hash { + if (_objectSchema.primaryKeyProperty) { + id primaryProperty = [self valueForKey:_objectSchema.primaryKeyProperty.name]; + + // modify the hash of our primary key value to avoid potential (although unlikely) collisions + return [primaryProperty hash] ^ 1; + } + else { + return [super hash]; + } +} + ++ (BOOL)shouldIncludeInDefaultSchema { + return RLMIsObjectSubclass(self); +} + ++ (NSString *)_realmObjectName { + return nil; +} + +- (id)mutableArrayValueForKey:(NSString *)key { + id obj = [self valueForKey:key]; + if ([obj isKindOfClass:[RLMArray class]]) { + return obj; + } + return [super mutableArrayValueForKey:key]; +} + +- (void)addObserver:(id)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + if (!_observationInfo) { + _observationInfo = new RLMObservationInfo(self); + } + _observationInfo->recordObserver(_row, _info, _objectSchema, keyPath); + + [super addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + if (_observationInfo) + _observationInfo->removeObserver(); +} + ++ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { + const char *className = class_getName(self); + const char accessorClassPrefix[] = "RLM:Managed"; + if (!strncmp(className, accessorClassPrefix, sizeof(accessorClassPrefix) - 1)) { + if ([class_getSuperclass(self.class) sharedSchema][key]) { + return NO; + } + } + + return [super automaticallyNotifiesObserversForKey:key]; +} + +#pragma mark - Thread Confined Protocol Conformance + +- (std::unique_ptr)makeThreadSafeReference { + Object object(_realm->_realm, *_info->objectSchema, _row); + realm::ThreadSafeReference reference = _realm->_realm->obtain_thread_safe_reference(std::move(object)); + return std::make_unique>(std::move(reference)); +} + +- (id)objectiveCMetadata { + return nil; +} + ++ (instancetype)objectWithThreadSafeReference:(std::unique_ptr)reference + metadata:(__unused id)metadata + realm:(RLMRealm *)realm { + REALM_ASSERT_DEBUG(dynamic_cast *>(reference.get())); + auto object_reference = static_cast *>(reference.get()); + + Object object = realm->_realm->resolve_thread_safe_reference(std::move(*object_reference)); + if (!object.is_valid()) { + return nil; + } + NSString *objectClassName = @(object.get_object_schema().name.c_str()); + + return RLMCreateObjectAccessor(realm, realm->_info[objectClassName], object.row().get_index()); +} + +@end + +RLMRealm *RLMObjectBaseRealm(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_realm : nil; +} + +RLMObjectSchema *RLMObjectBaseObjectSchema(__unsafe_unretained RLMObjectBase *object) { + return object ? object->_objectSchema : nil; +} + +id RLMObjectBaseObjectForKeyedSubscript(RLMObjectBase *object, NSString *key) { + if (!object) { + return nil; + } + + if (object->_realm) { + return RLMDynamicGetByName(object, key, false); + } + else { + return [object valueForKey:key]; + } +} + +void RLMObjectBaseSetObjectForKeyedSubscript(RLMObjectBase *object, NSString *key, id obj) { + if (!object) { + return; + } + + if (object->_realm) { + RLMDynamicValidatedSet(object, key, obj); + } + else { + [object setValue:obj forKey:key]; + } +} + + +BOOL RLMObjectBaseAreEqual(RLMObjectBase *o1, RLMObjectBase *o2) { + // if not the correct types throw + if ((o1 && ![o1 isKindOfClass:RLMObjectBase.class]) || (o2 && ![o2 isKindOfClass:RLMObjectBase.class])) { + @throw RLMException(@"Can only compare objects of class RLMObjectBase"); + } + // if identical object (or both are nil) + if (o1 == o2) { + return YES; + } + // if one is nil + if (o1 == nil || o2 == nil) { + return NO; + } + // if not in realm or differing realms + if (o1->_realm == nil || o1->_realm != o2->_realm) { + return NO; + } + // if either are detached + if (!o1->_row.is_attached() || !o2->_row.is_attached()) { + return NO; + } + // if table and index are the same + return o1->_row.get_table() == o2->_row.get_table() + && o1->_row.get_index() == o2->_row.get_index(); +} + +id RLMValidatedValueForProperty(id object, NSString *key, NSString *className) { + @try { + return [object valueForKey:key]; + } + @catch (NSException *e) { + if ([e.name isEqualToString:NSUndefinedKeyException]) { + @throw RLMException(@"Invalid value '%@' to initialize object of type '%@': missing key '%@'", + object, className, key); + } + @throw; + } +} + +Class RLMObjectUtilClass(BOOL isSwift) { + static Class objectUtilObjc = [RLMObjectUtil class]; + static Class objectUtilSwift = NSClassFromString(@"RealmSwiftObjectUtil"); + return isSwift && objectUtilSwift ? objectUtilSwift : objectUtilObjc; +} + +@implementation RLMObjectUtil + ++ (NSArray *)ignoredPropertiesForClass:(Class)cls { + return [cls ignoredProperties]; +} + ++ (NSArray *)indexedPropertiesForClass:(Class)cls { + return [cls indexedProperties]; +} + ++ (NSDictionary *)linkingObjectsPropertiesForClass:(Class)cls { + return [cls linkingObjectsProperties]; +} + ++ (NSDictionary *)linkingObjectProperties:(__unused id)object { + return nil; +} + ++ (NSArray *)getSwiftProperties:(__unused id)obj { + return nil; +} + ++ (NSDictionary *)getOptionalProperties:(__unused id)obj { + return nil; +} + ++ (NSArray *)requiredPropertiesForClass:(Class)cls { + return [cls requiredProperties]; +} + +@end + +@implementation RLMSwiftPropertyMetadata + ++ (instancetype)metadataForOtherProperty:(NSString *)propertyName { + RLMSwiftPropertyMetadata *md = [RLMSwiftPropertyMetadata new]; + md.propertyName = propertyName; + md.kind = RLMSwiftPropertyKindOther; + return md; +} + ++ (instancetype)metadataForListProperty:(NSString *)propertyName { + RLMSwiftPropertyMetadata *md = [RLMSwiftPropertyMetadata new]; + md.propertyName = propertyName; + md.kind = RLMSwiftPropertyKindList; + return md; +} + ++ (instancetype)metadataForLinkingObjectsProperty:(NSString *)propertyName + className:(NSString *)className + linkedPropertyName:(NSString *)linkedPropertyName { + RLMSwiftPropertyMetadata *md = [RLMSwiftPropertyMetadata new]; + md.propertyName = propertyName; + md.className = className; + md.linkedPropertyName = linkedPropertyName; + md.kind = RLMSwiftPropertyKindLinkingObjects; + return md; +} + ++ (instancetype)metadataForOptionalProperty:(NSString *)propertyName type:(RLMPropertyType)type { + RLMSwiftPropertyMetadata *md = [RLMSwiftPropertyMetadata new]; + md.propertyName = propertyName; + md.propertyType = type; + md.kind = RLMSwiftPropertyKindOptional; + return md; +} + ++ (instancetype)metadataForNilLiteralOptionalProperty:(NSString *)propertyName { + RLMSwiftPropertyMetadata *md = [RLMSwiftPropertyMetadata new]; + md.propertyName = propertyName; + md.kind = RLMSwiftPropertyKindNilLiteralOptional; + return md; +} + +@end