From 3b31a1c87dea853336363e5a6646f50a2aaf7ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bromo=CC=88?= Date: Wed, 28 Nov 2018 10:28:14 +0100 Subject: [PATCH 1/3] Fixed a crash when setting the success/error (in Swift) of an MTLValueTransformer, caused by capturing the autoreleased error reference in the blocks and the error reference being deallocated prematurely. Passing a local tmpError that is then assigned to the error reference avoids this. --- .../MTLManagedObjectAdapter.m | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/MTLManagedObjectAdapter/MTLManagedObjectAdapter.m b/MTLManagedObjectAdapter/MTLManagedObjectAdapter.m index 7dcdc22..b19ffcc 100644 --- a/MTLManagedObjectAdapter/MTLManagedObjectAdapter.m +++ b/MTLManagedObjectAdapter/MTLManagedObjectAdapter.m @@ -166,12 +166,14 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( // any cycles when processing its relationships. CFDictionaryAddValue(processedObjects, (__bridge void *)managedObject, (__bridge void *)model); + __block NSError *tmpError; + BOOL (^setValueForKey)(NSString *, id) = ^(NSString *key, id value) { // 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 replaceableValue = value; - if (![model validateValue:&replaceableValue forKey:key error:error]) return NO; + if (![model validateValue:&replaceableValue forKey:key error:&tmpError]) return NO; [model setValue:replaceableValue forKey:key]; return YES; @@ -191,7 +193,7 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( id errorHandlingTransformer = (id)transformer; BOOL success = YES; - value = [errorHandlingTransformer transformedValue:value success:&success error:error]; + value = [errorHandlingTransformer transformedValue:value success:&success error:&tmpError]; if (!success) return NO; } else if (transformer != nil) { @@ -213,7 +215,7 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( NSMutableArray *models = [NSMutableArray arrayWithCapacity:[relationshipCollection count]]; for (NSManagedObject *nestedObject in relationshipCollection) { - id model = [self.class modelOfClass:nestedClass fromManagedObject:nestedObject processedObjects:processedObjects error:error]; + id model = [self.class modelOfClass:nestedClass fromManagedObject:nestedObject processedObjects:processedObjects error:&tmpError]; if (model == nil) return nil; [models addObject:model]; @@ -233,7 +235,7 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( if (nestedObject == nil) return YES; - id model = [self.class modelOfClass:nestedClass fromManagedObject:nestedObject processedObjects:processedObjects error:error]; + id model = [self.class modelOfClass:nestedClass fromManagedObject:nestedObject processedObjects:processedObjects error:&tmpError]; if (model == nil) return NO; return setValueForKey(propertyKey, model); @@ -242,17 +244,14 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( BOOL (^deserializeProperty)(NSPropertyDescription *) = ^(NSPropertyDescription *propertyDescription) { if (propertyDescription == nil) { - if (error != NULL) { - NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"No property by name \"%@\" exists on the entity.", @""), managedObjectKey]; - - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Could not deserialize managed object", @""), - NSLocalizedFailureReasonErrorKey: failureReason, - }; + NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"No property by name \"%@\" exists on the entity.", @""), managedObjectKey]; - *error = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorInvalidManagedObjectKey userInfo:userInfo]; - } + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Could not deserialize managed object", @""), + NSLocalizedFailureReasonErrorKey: failureReason, + }; + tmpError = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorInvalidManagedObjectKey userInfo:userInfo]; return NO; } @@ -263,22 +262,24 @@ - (id)modelFromManagedObject:(NSManagedObject *)managedObject processedObjects:( } else if ([propertyClassName isEqual:@"NSRelationshipDescription"]) { return deserializeRelationship((id)propertyDescription); } else { - if (error != NULL) { - NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Property descriptions of class %@ are unsupported.", @""), propertyClassName]; - - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Could not deserialize managed object", @""), - NSLocalizedFailureReasonErrorKey: failureReason, - }; + NSString *failureReason = [NSString stringWithFormat:NSLocalizedString(@"Property descriptions of class %@ are unsupported.", @""), propertyClassName]; - *error = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorUnsupportedManagedObjectPropertyType userInfo:userInfo]; - } + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Could not deserialize managed object", @""), + NSLocalizedFailureReasonErrorKey: failureReason, + }; + tmpError = [NSError errorWithDomain:MTLManagedObjectAdapterErrorDomain code:MTLManagedObjectAdapterErrorUnsupportedManagedObjectPropertyType userInfo:userInfo]; return NO; } }; - if (!deserializeProperty(managedObjectProperties[managedObjectKey])) return nil; + if (!deserializeProperty(managedObjectProperties[managedObjectKey])) { + if (tmpError && error) { + *error = tmpError; + } + return nil; + } } return model; @@ -452,7 +453,7 @@ - (id)managedObjectFromModel:(id)model insertingInt id errorHandlingTransformer = (id)transformer; BOOL success = YES; - transformedValue = [errorHandlingTransformer reverseTransformedValue:value success:&success error:error]; + transformedValue = [errorHandlingTransformer reverseTransformedValue:value success:&success error:&tmpError]; if (!success) return NO; } else { From eae60888fe179c52b6f9b7ddde107e2a53f275b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bromo=CC=88?= Date: Wed, 28 Nov 2018 10:37:43 +0100 Subject: [PATCH 2/3] Ensure property attributes don't leak (https://github.com/jspahrsummers/libextobjc/commit/31927ddccd68564addcf310741b0c252225ddcea) --- MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m b/MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m index 7b8804e..3eb6e5f 100644 --- a/MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m +++ b/MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m @@ -53,7 +53,7 @@ if (!next) { fprintf(stderr, "ERROR: Could not read class name in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); - return NULL; + goto errorOut; } if (className != next) { From 390e564defe3bc4fc49a324ea385936ab5f211d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bromo=CC=88?= Date: Wed, 28 Nov 2018 10:40:05 +0100 Subject: [PATCH 3/3] Added a podspec and increased the version to 1.0.4. --- MTLManagedObjectAdapter.podspec | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 MTLManagedObjectAdapter.podspec diff --git a/MTLManagedObjectAdapter.podspec b/MTLManagedObjectAdapter.podspec new file mode 100644 index 0000000..25ea72a --- /dev/null +++ b/MTLManagedObjectAdapter.podspec @@ -0,0 +1,25 @@ +Pod::Spec.new do |s| + s.name = "MTLManagedObjectAdapter" + s.version = "1.0.4" + s.license = "MIT" + s.summary = "Model framework for Cocoa and Cocoa Touch." + s.homepage = "https://github.com/Mantle/Mantle" + s.authors = { "GitHub" => "support@github.com" } + s.source = { :git => "https://github.com/peroper/MTLManagedObjectAdapter.git", :tag => s.version } + s.requires_arc = true + s.platforms = { + :ios => "5.0", + :osx => "10.7", + :watchos => "2.0", + :tvos => "9.0" + } + s.source_files = "MTLManagedObjectAdapter" + s.dependency "Mantle", "~> 2.0" + s.frameworks = "Foundation", "CoreData" + s.prepare_command = "PREFIX=\"mtl_moa_\"\n# Add prefix to header imports\next_header_prefix_src() {\n SOURCE_FILE=$1\n EXT_HEADER_NAME=$2\n sed -i.bak \"s/\"${EXT_HEADER_NAME}\"/\"${PREFIX}${EXT_HEADER_NAME}\"/g\" ${SOURCE_FILE} && rm ${SOURCE_FILE}.bak\n}\next_header_prefix_src MTLManagedObjectAdapter/MTLManagedObjectAdapter.m EXTRuntimeExtensions.h\next_header_prefix_src MTLManagedObjectAdapter/MTLManagedObjectAdapter.m EXTScope.h\next_header_prefix_src MTLManagedObjectAdapter/extobjc/EXTRuntimeExtensions.m EXTRuntimeExtensions.h\next_header_prefix_src MTLManagedObjectAdapter/extobjc/EXTScope.m EXTScope.h\n# Change header name\next_header_prefix_mv() {\n SOURCE_FILE=$1\n FILE_NAME=`basename ${SOURCE_FILE}`\n DIR_NAME=`dirname ${SOURCE_FILE}`\n mv ${SOURCE_FILE} `dirname ${SOURCE_FILE}`/${PREFIX}`basename ${SOURCE_FILE}`\n}\nexport -f ext_header_prefix_mv\nexport PREFIX=${PREFIX}\nfind MTLManagedObjectAdapter/extobjc -name \"*.h\" -exec bash -c 'ext_header_prefix_mv \"$0\"' {} \\;\nunset ext_header_prefix_mv\nunset PREFIX" + s.default_subspec = 'extobjc' + s.subspec 'extobjc' do |s| + s.source_files = "MTLManagedObjectAdapter/extobjc" + s.private_header_files = "MTLManagedObjectAdapter/extobjc/*.h" + end +end