From eee1417be2f4277069c2db11dffbff67fa974db4 Mon Sep 17 00:00:00 2001 From: Sam Stigler Date: Tue, 14 Apr 2015 20:32:28 -0500 Subject: [PATCH 1/3] Deletes unused parameter from MMRecord's method for deleting orphaned records. --- Source/MMRecord/MMRecord.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/MMRecord/MMRecord.m b/Source/MMRecord/MMRecord.m index 10948ff..e403648 100644 --- a/Source/MMRecord/MMRecord.m +++ b/Source/MMRecord/MMRecord.m @@ -527,7 +527,6 @@ + (void)completeRequestForResponse:(id)responseObject [self conditionallyDeleteRecordsOphanedByResponse:responseObject populatedRecords:state.records options:options - state:state context:state.backgroundContext]; [self performCachingForRecords:state.records @@ -836,7 +835,6 @@ + (NSArray *)mainContextRecordsFromObjectIDs:(NSArray *)objectIDs + (void)conditionallyDeleteRecordsOphanedByResponse:(id)responseObject populatedRecords:(NSArray *)populatedRecords options:(MMRecordOptions *)options - state:(MMRecordRequestState *)state context:(NSManagedObjectContext *)context { if (options.deleteOrphanedRecordBlock != nil) { NSArray *orphanedRecords = [self orphanedRecordsFromContext:context populatedRecords:populatedRecords]; From 1010c594c621f788b7f421b425576c061acde12a Mon Sep 17 00:00:00 2001 From: Sam Stigler Date: Tue, 14 Apr 2015 20:33:06 -0500 Subject: [PATCH 2/3] Minor spelling correction --- Source/MMRecord/MMRecord.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/MMRecord/MMRecord.m b/Source/MMRecord/MMRecord.m index e403648..e3bc3be 100644 --- a/Source/MMRecord/MMRecord.m +++ b/Source/MMRecord/MMRecord.m @@ -524,10 +524,10 @@ + (void)completeRequestForResponse:(id)responseObject state:state context:state.backgroundContext]; - [self conditionallyDeleteRecordsOphanedByResponse:responseObject - populatedRecords:state.records - options:options - context:state.backgroundContext]; + [self conditionallyDeleteRecordsOrphanedByResponse:responseObject + populatedRecords:state.records + options:options + context:state.backgroundContext]; [self performCachingForRecords:state.records fromResponseObject:state.responseObject @@ -832,10 +832,10 @@ + (NSArray *)mainContextRecordsFromObjectIDs:(NSArray *)objectIDs #pragma mark - Orphan Deletion Methods -+ (void)conditionallyDeleteRecordsOphanedByResponse:(id)responseObject - populatedRecords:(NSArray *)populatedRecords - options:(MMRecordOptions *)options - context:(NSManagedObjectContext *)context { ++ (void)conditionallyDeleteRecordsOrphanedByResponse:(id)responseObject + populatedRecords:(NSArray *)populatedRecords + options:(MMRecordOptions *)options + context:(NSManagedObjectContext *)context { if (options.deleteOrphanedRecordBlock != nil) { NSArray *orphanedRecords = [self orphanedRecordsFromContext:context populatedRecords:populatedRecords]; From 95a7cd07c6d465fc6bfd9410bcfe8372d791cf0f Mon Sep 17 00:00:00 2001 From: Sam Stigler Date: Tue, 14 Apr 2015 21:38:39 -0500 Subject: [PATCH 3/3] Extracts orphan deletion into its own class. --- .../project.pbxproj | 6 ++ .../project.pbxproj | 6 ++ .../project.pbxproj | 8 ++ .../project.pbxproj | 6 ++ .../project.pbxproj | 6 ++ .../MMRecordTwitter.xcodeproj/project.pbxproj | 6 ++ MMRecord.xcworkspace/contents.xcworkspacedata | 6 ++ Source/MMRecord/MMRecord.m | 57 ++---------- Source/MMRecord/MMRecordOrphanDeleter.h | 54 ++++++++++++ Source/MMRecord/MMRecordOrphanDeleter.m | 87 +++++++++++++++++++ 10 files changed, 193 insertions(+), 49 deletions(-) create mode 100644 Source/MMRecord/MMRecordOrphanDeleter.h create mode 100644 Source/MMRecord/MMRecordOrphanDeleter.m diff --git a/Examples/MMRecordAppDotNet/MMRecordAppDotNet.xcodeproj/project.pbxproj b/Examples/MMRecordAppDotNet/MMRecordAppDotNet.xcodeproj/project.pbxproj index bbe40be..15a6eff 100644 --- a/Examples/MMRecordAppDotNet/MMRecordAppDotNet.xcodeproj/project.pbxproj +++ b/Examples/MMRecordAppDotNet/MMRecordAppDotNet.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 55F9525A165C7F520060851E /* PostCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55F95259165C7F520060851E /* PostCell.xib */; }; 55F95260165C82B90060851E /* PostCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 55F9525F165C82B90060851E /* PostCell.m */; }; 55F95262165C85870060851E /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 55F95261165C85870060851E /* avatar.png */; }; + 57F44CC51ADE049C00C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CC41ADE049C00C83C53 /* MMRecordOrphanDeleter.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -235,6 +236,8 @@ 55F9525E165C82B90060851E /* PostCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PostCell.h; sourceTree = ""; }; 55F9525F165C82B90060851E /* PostCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PostCell.m; sourceTree = ""; }; 55F95261165C85870060851E /* avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = avatar.png; sourceTree = ""; }; + 57F44CC31ADE049C00C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CC41ADE049C00C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -484,6 +487,8 @@ 2648FBE8195AFC5B009A6CBB /* MMRecordDebugger.m */, 5569077916FA750D0040D191 /* MMRecordMarshaler.h */, 5569077A16FA750D0040D191 /* MMRecordMarshaler.m */, + 57F44CC31ADE049C00C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CC41ADE049C00C83C53 /* MMRecordOrphanDeleter.m */, 267469EA16A1C226006A6A81 /* MMRecordProtoRecord.h */, 267469EB16A1C226006A6A81 /* MMRecordProtoRecord.m */, 55211F6816F179E300729C51 /* MMRecordRepresentation.h */, @@ -690,6 +695,7 @@ 55AA657218FB1F610018B4A0 /* FBTweakCategory.m in Sources */, 55E712BE16FE15E300EC1159 /* ADNPageManager.m in Sources */, 55AA657118FB1F610018B4A0 /* FBTweak.m in Sources */, + 57F44CC51ADE049C00C83C53 /* MMRecordOrphanDeleter.m in Sources */, 55E712C216FE4A4000EC1159 /* ADNUsersViewController.m in Sources */, 55E712C716FE4A6D00EC1159 /* UserCell.m in Sources */, 55AA656F18FB1F610018B4A0 /* _FBTweakCollectionViewController.m in Sources */, diff --git a/Examples/MMRecordAtlassian/MMRecordAtlassian.xcodeproj/project.pbxproj b/Examples/MMRecordAtlassian/MMRecordAtlassian.xcodeproj/project.pbxproj index 9e67cd4..217ed50 100644 --- a/Examples/MMRecordAtlassian/MMRecordAtlassian.xcodeproj/project.pbxproj +++ b/Examples/MMRecordAtlassian/MMRecordAtlassian.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 55A1CC26195B9C6A007FBCB8 /* MMServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 55A1CC19195B9C6A007FBCB8 /* MMServer.m */; }; 55A1CC27195B9C6A007FBCB8 /* MMServerPageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 55A1CC1B195B9C6A007FBCB8 /* MMServerPageManager.m */; }; 55A1CC28195B9C6A007FBCB8 /* MMJSONServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 55A1CC1E195B9C6A007FBCB8 /* MMJSONServer.m */; }; + 57F44CC81ADE04DC00C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CC71ADE04DC00C83C53 /* MMRecordOrphanDeleter.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -71,6 +72,8 @@ 55A1CC1B195B9C6A007FBCB8 /* MMServerPageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMServerPageManager.m; sourceTree = ""; }; 55A1CC1D195B9C6A007FBCB8 /* MMJSONServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMJSONServer.h; sourceTree = ""; }; 55A1CC1E195B9C6A007FBCB8 /* MMJSONServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMJSONServer.m; sourceTree = ""; }; + 57F44CC61ADE04DC00C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CC71ADE04DC00C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -200,6 +203,8 @@ 55A1CC0F195B9C6A007FBCB8 /* MMRecordDebugger.m */, 55A1CC10195B9C6A007FBCB8 /* MMRecordMarshaler.h */, 55A1CC11195B9C6A007FBCB8 /* MMRecordMarshaler.m */, + 57F44CC61ADE04DC00C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CC71ADE04DC00C83C53 /* MMRecordOrphanDeleter.m */, 55A1CC12195B9C6A007FBCB8 /* MMRecordProtoRecord.h */, 55A1CC13195B9C6A007FBCB8 /* MMRecordProtoRecord.m */, 55A1CC14195B9C6A007FBCB8 /* MMRecordRepresentation.h */, @@ -298,6 +303,7 @@ files = ( 55A1CC25195B9C6A007FBCB8 /* MMRecordResponse.m in Sources */, 55A1CC21195B9C6A007FBCB8 /* MMRecordDebugger.m in Sources */, + 57F44CC81ADE04DC00C83C53 /* MMRecordOrphanDeleter.m in Sources */, 26FC7C38195A64600066A195 /* Link.swift in Sources */, 55A1CC22195B9C6A007FBCB8 /* MMRecordMarshaler.m in Sources */, 26FC7C32195A641F0066A195 /* Plan.swift in Sources */, diff --git a/Examples/MMRecordFoursquare/MMRecordFoursquare/MMRecordFoursquare.xcodeproj/project.pbxproj b/Examples/MMRecordFoursquare/MMRecordFoursquare/MMRecordFoursquare.xcodeproj/project.pbxproj index 6e470b4..8cfaa4b 100644 --- a/Examples/MMRecordFoursquare/MMRecordFoursquare/MMRecordFoursquare.xcodeproj/project.pbxproj +++ b/Examples/MMRecordFoursquare/MMRecordFoursquare/MMRecordFoursquare.xcodeproj/project.pbxproj @@ -60,6 +60,8 @@ 55DB69CC184E66F400677CEA /* Venue.json in Resources */ = {isa = PBXBuildFile; fileRef = 55DB69CB184E66F400677CEA /* Venue.json */; }; 55F8C4BB1848F8E000037D45 /* AFMMRecordResponseSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 55F8C4BA1848F8E000037D45 /* AFMMRecordResponseSerializer.m */; }; 55FB3C1A18C1A10400B861BA /* AFMMRecordSessionManagerServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FB3C1918C1A10400B861BA /* AFMMRecordSessionManagerServer.m */; }; + 57F44CCB1ADE050000C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CCA1ADE050000C83C53 /* MMRecordOrphanDeleter.m */; }; + 57F44CCC1ADE050000C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CCA1ADE050000C83C53 /* MMRecordOrphanDeleter.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -165,6 +167,8 @@ 55F8C4BA1848F8E000037D45 /* AFMMRecordResponseSerializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFMMRecordResponseSerializer.m; sourceTree = ""; }; 55FB3C1818C1A10400B861BA /* AFMMRecordSessionManagerServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFMMRecordSessionManagerServer.h; sourceTree = ""; }; 55FB3C1918C1A10400B861BA /* AFMMRecordSessionManagerServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFMMRecordSessionManagerServer.m; sourceTree = ""; }; + 57F44CC91ADE050000C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CCA1ADE050000C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -394,6 +398,8 @@ 26ECD8A7195B3E8800DBB3C5 /* MMRecordDebugger.m */, 55D2789718297E01008CB6B4 /* MMRecordMarshaler.h */, 55D2789818297E01008CB6B4 /* MMRecordMarshaler.m */, + 57F44CC91ADE050000C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CCA1ADE050000C83C53 /* MMRecordOrphanDeleter.m */, 55D2789918297E01008CB6B4 /* MMRecordProtoRecord.h */, 55D2789A18297E01008CB6B4 /* MMRecordProtoRecord.m */, 55D2789B18297E01008CB6B4 /* MMRecordRepresentation.h */, @@ -551,6 +557,7 @@ 55D2785D1829769B008CB6B4 /* AFURLResponseSerialization.m in Sources */, 55D2785B1829769B008CB6B4 /* AFURLConnectionOperation.m in Sources */, 55D27866182977F5008CB6B4 /* MMFoursquareSessionManager.m in Sources */, + 57F44CCB1ADE050000C83C53 /* MMRecordOrphanDeleter.m in Sources */, 55D2785A1829769B008CB6B4 /* AFSecurityPolicy.m in Sources */, 55D278AD18297E01008CB6B4 /* MMServerPageManager.m in Sources */, 55D278581829769B008CB6B4 /* AFHTTPSessionManager.m in Sources */, @@ -583,6 +590,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 57F44CCC1ADE050000C83C53 /* MMRecordOrphanDeleter.m in Sources */, 55D278361829765E008CB6B4 /* MMRecordFoursquareTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Examples/MMRecordInstagram/MMRecordInstagram.xcodeproj/project.pbxproj b/Examples/MMRecordInstagram/MMRecordInstagram.xcodeproj/project.pbxproj index 55e2a19..bd50789 100644 --- a/Examples/MMRecordInstagram/MMRecordInstagram.xcodeproj/project.pbxproj +++ b/Examples/MMRecordInstagram/MMRecordInstagram.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 55C898C417068B2C004E3C50 /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898BA17068B2C004E3C50 /* Icon-Small@2x.png */; }; 55C898C717068B2C004E3C50 /* iTunesArtwork.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898BD17068B2C004E3C50 /* iTunesArtwork.png */; }; 55C898C817068B2C004E3C50 /* iTunesArtwork@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898BE17068B2C004E3C50 /* iTunesArtwork@2x.png */; }; + 57F44CD61ADE063400C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CD51ADE063400C83C53 /* MMRecordOrphanDeleter.m */; }; 9FABD8A516FA7DC700184BA5 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FABD8A416FA7DC700184BA5 /* UIKit.framework */; }; 9FABD8A716FA7DC700184BA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FABD8A616FA7DC700184BA5 /* Foundation.framework */; }; 9FABD8A916FA7DC700184BA5 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9FABD8A816FA7DC700184BA5 /* CoreGraphics.framework */; }; @@ -106,6 +107,8 @@ 55C898BA17068B2C004E3C50 /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = ""; }; 55C898BD17068B2C004E3C50 /* iTunesArtwork.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iTunesArtwork.png; sourceTree = ""; }; 55C898BE17068B2C004E3C50 /* iTunesArtwork@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iTunesArtwork@2x.png"; sourceTree = ""; }; + 57F44CD41ADE063400C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CD51ADE063400C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; 9FABD8A116FA7DC700184BA5 /* MMRecordInstagram.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MMRecordInstagram.app; sourceTree = BUILT_PRODUCTS_DIR; }; 9FABD8A416FA7DC700184BA5 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 9FABD8A616FA7DC700184BA5 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; @@ -386,6 +389,8 @@ 26ECD8AA195B3EA200DBB3C5 /* MMRecordDebugger.m */, 9FABD98316FA93EF00184BA5 /* MMRecordMarshaler.h */, 9FABD98416FA93EF00184BA5 /* MMRecordMarshaler.m */, + 57F44CD41ADE063400C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CD51ADE063400C83C53 /* MMRecordOrphanDeleter.m */, 9FABD98816FA93EF00184BA5 /* MMRecordProtoRecord.h */, 9FABD98916FA93EF00184BA5 /* MMRecordProtoRecord.m */, 9FABD98A16FA93EF00184BA5 /* MMRecordRepresentation.h */, @@ -560,6 +565,7 @@ 9FABD99216FA93EF00184BA5 /* MMRecord.m in Sources */, 9FABD99316FA93EF00184BA5 /* MMRecordCache.m in Sources */, 9FABD99716FA93EF00184BA5 /* MMRecordMarshaler.m in Sources */, + 57F44CD61ADE063400C83C53 /* MMRecordOrphanDeleter.m in Sources */, 9FABD99916FA93EF00184BA5 /* MMRecordProtoRecord.m in Sources */, 9FABD99A16FA93EF00184BA5 /* MMRecordRepresentation.m in Sources */, 9FABD99B16FA93EF00184BA5 /* MMRecordResponse.m in Sources */, diff --git a/Examples/MMRecordPerformance/MMRecordPerformance.xcodeproj/project.pbxproj b/Examples/MMRecordPerformance/MMRecordPerformance.xcodeproj/project.pbxproj index 1ce32d9..2de739c 100644 --- a/Examples/MMRecordPerformance/MMRecordPerformance.xcodeproj/project.pbxproj +++ b/Examples/MMRecordPerformance/MMRecordPerformance.xcodeproj/project.pbxproj @@ -74,6 +74,7 @@ 55F9525A165C7F520060851E /* PostCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 55F95259165C7F520060851E /* PostCell.xib */; }; 55F95260165C82B90060851E /* PostCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 55F9525F165C82B90060851E /* PostCell.m */; }; 55F95262165C85870060851E /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 55F95261165C85870060851E /* avatar.png */; }; + 57F44CD21ADE05AA00C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CD11ADE05AA00C83C53 /* MMRecordOrphanDeleter.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -182,6 +183,8 @@ 55F9525E165C82B90060851E /* PostCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PostCell.h; sourceTree = ""; }; 55F9525F165C82B90060851E /* PostCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PostCell.m; sourceTree = ""; }; 55F95261165C85870060851E /* avatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = avatar.png; sourceTree = ""; }; + 57F44CD01ADE05AA00C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CD11ADE05AA00C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -380,6 +383,8 @@ 26ECD8B0195B3EC900DBB3C5 /* MMRecordDebugger.m */, 5569077916FA750D0040D191 /* MMRecordMarshaler.h */, 5569077A16FA750D0040D191 /* MMRecordMarshaler.m */, + 57F44CD01ADE05AA00C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CD11ADE05AA00C83C53 /* MMRecordOrphanDeleter.m */, 267469EA16A1C226006A6A81 /* MMRecordProtoRecord.h */, 267469EB16A1C226006A6A81 /* MMRecordProtoRecord.m */, 55211F6816F179E300729C51 /* MMRecordRepresentation.h */, @@ -554,6 +559,7 @@ 55F95246165C77380060851E /* AFJSONRequestOperation.m in Sources */, 55F95247165C77380060851E /* AFNetworkActivityIndicatorManager.m in Sources */, 55F95248165C77380060851E /* AFPropertyListRequestOperation.m in Sources */, + 57F44CD21ADE05AA00C83C53 /* MMRecordOrphanDeleter.m in Sources */, 55F95249165C77380060851E /* AFURLConnectionOperation.m in Sources */, 55F9524A165C77380060851E /* AFXMLRequestOperation.m in Sources */, 55F9524B165C77380060851E /* UIImageView+AFNetworking.m in Sources */, diff --git a/Examples/MMRecordTwitter/MMRecordTwitter.xcodeproj/project.pbxproj b/Examples/MMRecordTwitter/MMRecordTwitter.xcodeproj/project.pbxproj index 9ead485..fa3e96c 100644 --- a/Examples/MMRecordTwitter/MMRecordTwitter.xcodeproj/project.pbxproj +++ b/Examples/MMRecordTwitter/MMRecordTwitter.xcodeproj/project.pbxproj @@ -64,6 +64,7 @@ 55C898DB17068B83004E3C50 /* Icon-Small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898D317068B83004E3C50 /* Icon-Small@2x.png */; }; 55C898DC17068B83004E3C50 /* iTunesArtwork.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898D417068B83004E3C50 /* iTunesArtwork.png */; }; 55C898DD17068B83004E3C50 /* iTunesArtwork@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 55C898D517068B83004E3C50 /* iTunesArtwork@2x.png */; }; + 57F44CCF1ADE059000C83C53 /* MMRecordOrphanDeleter.m in Sources */ = {isa = PBXBuildFile; fileRef = 57F44CCE1ADE059000C83C53 /* MMRecordOrphanDeleter.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -155,6 +156,8 @@ 55C898D317068B83004E3C50 /* Icon-Small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small@2x.png"; sourceTree = ""; }; 55C898D417068B83004E3C50 /* iTunesArtwork.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iTunesArtwork.png; sourceTree = ""; }; 55C898D517068B83004E3C50 /* iTunesArtwork@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iTunesArtwork@2x.png"; sourceTree = ""; }; + 57F44CCD1ADE059000C83C53 /* MMRecordOrphanDeleter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMRecordOrphanDeleter.h; sourceTree = ""; }; + 57F44CCE1ADE059000C83C53 /* MMRecordOrphanDeleter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMRecordOrphanDeleter.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -209,6 +212,8 @@ 26ECD8AD195B3EB600DBB3C5 /* MMRecordDebugger.m */, 55325F2716FD55910074C313 /* MMRecordMarshaler.h */, 55325F2816FD55910074C313 /* MMRecordMarshaler.m */, + 57F44CCD1ADE059000C83C53 /* MMRecordOrphanDeleter.h */, + 57F44CCE1ADE059000C83C53 /* MMRecordOrphanDeleter.m */, 55325F2916FD55910074C313 /* MMRecordProtoRecord.h */, 55325F2A16FD55910074C313 /* MMRecordProtoRecord.m */, 55325F2B16FD55910074C313 /* MMRecordRepresentation.h */, @@ -494,6 +499,7 @@ 55325F3616FD55910074C313 /* MMRecordCache.m in Sources */, 55325F3916FD55910074C313 /* MMRecordMarshaler.m in Sources */, 55325F3A16FD55910074C313 /* MMRecordProtoRecord.m in Sources */, + 57F44CCF1ADE059000C83C53 /* MMRecordOrphanDeleter.m in Sources */, 55325F3B16FD55910074C313 /* MMRecordRepresentation.m in Sources */, 55325F3C16FD55910074C313 /* MMRecordResponse.m in Sources */, 55325F3D16FD55910074C313 /* MMServer.m in Sources */, diff --git a/MMRecord.xcworkspace/contents.xcworkspacedata b/MMRecord.xcworkspace/contents.xcworkspacedata index 8e5cf09..0f2ba0f 100644 --- a/MMRecord.xcworkspace/contents.xcworkspacedata +++ b/MMRecord.xcworkspace/contents.xcworkspacedata @@ -44,6 +44,12 @@ + + + + diff --git a/Source/MMRecord/MMRecord.m b/Source/MMRecord/MMRecord.m index e3bc3be..25d4539 100644 --- a/Source/MMRecord/MMRecord.m +++ b/Source/MMRecord/MMRecord.m @@ -23,6 +23,7 @@ #import "MMRecord.h" #import "MMRecordCache.h" +#import "MMRecordOrphanDeleter.h" #import "MMRecordRepresentation.h" #import "MMRecordResponse.h" #import "MMServer.h" @@ -830,62 +831,20 @@ + (NSArray *)mainContextRecordsFromObjectIDs:(NSArray *)objectIDs } -#pragma mark - Orphan Deletion Methods +#pragma mark - Orphan Deletion Method + (void)conditionallyDeleteRecordsOrphanedByResponse:(id)responseObject populatedRecords:(NSArray *)populatedRecords options:(MMRecordOptions *)options context:(NSManagedObjectContext *)context { - if (options.deleteOrphanedRecordBlock != nil) { - NSArray *orphanedRecords = [self orphanedRecordsFromContext:context populatedRecords:populatedRecords]; - - BOOL stop = NO; - - for (MMRecord *orphanedRecord in orphanedRecords) { - BOOL deleteOrphan = options.deleteOrphanedRecordBlock(orphanedRecord, populatedRecords, responseObject, &stop); - - if (deleteOrphan) { - [context deleteObject:orphanedRecord]; - } - - if (stop) { - break; - } - } - } -} - -+ (NSArray *)orphanedRecordsFromContext:(NSManagedObjectContext *)context - populatedRecords:(NSArray *)populatedRecords { - NSMutableArray *populatedObjectIDs = [NSMutableArray array]; - NSMutableSet *orphanedObjectIDs = [NSMutableSet set]; - - for (MMRecord *record in populatedRecords) { - [populatedObjectIDs addObject:[record objectID]]; - } NSString *entityName = [[context MMRecord_entityForClass:self] name]; - - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName]; - fetchRequest.fetchBatchSize = 20; - - NSArray *allRecords = [context executeFetchRequest:fetchRequest error:NULL]; - - for (MMRecord *record in allRecords) { - [orphanedObjectIDs addObject:[record objectID]]; - } - - for (NSManagedObjectID *objectID in populatedObjectIDs) { - [orphanedObjectIDs removeObject:objectID]; - } - - NSMutableArray *orphanedRecords = [NSMutableArray array]; - - for (NSManagedObjectID *orphanedObjectID in orphanedObjectIDs) { - [orphanedRecords addObject:[context objectWithID:orphanedObjectID]]; - } - - return orphanedRecords; + [MMRecordOrphanDeleter + conditionallyDeleteRecordsWithEntityName:entityName + orphanedByResponse:responseObject + populatedRecords:populatedRecords + deleteRule:options.deleteOrphanedRecordBlock + context:context]; } diff --git a/Source/MMRecord/MMRecordOrphanDeleter.h b/Source/MMRecord/MMRecordOrphanDeleter.h new file mode 100644 index 0000000..bc2370d --- /dev/null +++ b/Source/MMRecord/MMRecordOrphanDeleter.h @@ -0,0 +1,54 @@ +// MMRecordOrphanDeleter.h +// +// Copyright (c) 2015 Mutual Mobile (http://www.mutualmobile.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "MMRecord.h" + +/** + This class encapsulates MMRecord's orphan-deletion logic, and is designed to be mostly decoupled + from the rest of the library. It acts by looking at the @c deleteOrphanedRecordBlock that is + (optionally) part of the @c MMRecordOptions that are passed into this class's one public method. + Default behavior (if the @c deleteOrphanedRecordBlock is nil) is to not delete orphans. + */ +@interface MMRecordOrphanDeleter : NSObject + +/** + Conditionally deletes any records with the specified @c entityName that were orphaned by the + specified @c responseObject. + + @param entityName The name of the entity in question + @param responseObject The full response object that came back from the server request to get the + updated records. Optional. + @param populatedRecords The records that have been populated with the contents of @c responseObject. + @param deleteRule A @c MMRecordOptionsDeleteOrphanedRecordBlock that encapsulates your logic for whether to delete an orphan. Return YES for "delete", and NO for "don't delete". Optional; defaults to NO. + @param context The @c NSManagedObjectContext you are working in. + + @pre @c responseObject has already been imported (sans the orphan deletion) into @c context, and the results of that import are in the @c populatedRecords array. + */ ++ (void)conditionallyDeleteRecordsWithEntityName:(NSString *)entityName + orphanedByResponse:(id)responseObject + populatedRecords:(NSArray *)populatedRecords + deleteRule:(MMRecordOptionsDeleteOrphanedRecordBlock)deleteRule + context:(NSManagedObjectContext *)context; + +@end diff --git a/Source/MMRecord/MMRecordOrphanDeleter.m b/Source/MMRecord/MMRecordOrphanDeleter.m new file mode 100644 index 0000000..999924e --- /dev/null +++ b/Source/MMRecord/MMRecordOrphanDeleter.m @@ -0,0 +1,87 @@ +// MMRecordOrphanDeleter.m +// +// Copyright (c) 2015 Mutual Mobile (http://www.mutualmobile.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "MMRecordOrphanDeleter.h" + +@implementation MMRecordOrphanDeleter + ++ (void)conditionallyDeleteRecordsWithEntityName:(NSString *)entityName + orphanedByResponse:(id)responseObject + populatedRecords:(NSArray *)populatedRecords + deleteRule:(MMRecordOptionsDeleteOrphanedRecordBlock)deleteRule + context:(NSManagedObjectContext *)context { + + NSParameterAssert(entityName != nil); + NSParameterAssert(context != nil); + + if (deleteRule != nil) { + NSArray *orphanedRecords = [self orphanedRecordsFromContext:context populatedRecords:populatedRecords entityName: entityName]; + + BOOL stop = NO; + + for (MMRecord *orphanedRecord in orphanedRecords) { + BOOL deleteOrphan = deleteRule(orphanedRecord, populatedRecords, responseObject, &stop); + + if (deleteOrphan) { + [context deleteObject:orphanedRecord]; + } + + if (stop) { + break; + } + } + } +} + ++ (NSArray *)orphanedRecordsFromContext:(NSManagedObjectContext *)context + populatedRecords:(NSArray *)populatedRecords + entityName:(NSString *)entityName { + NSMutableArray *populatedObjectIDs = [NSMutableArray array]; + NSMutableSet *orphanedObjectIDs = [NSMutableSet set]; + + for (MMRecord *record in populatedRecords) { + [populatedObjectIDs addObject:[record objectID]]; + } + + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName]; + fetchRequest.fetchBatchSize = 20; + + NSArray *allRecords = [context executeFetchRequest:fetchRequest error:NULL]; + + for (MMRecord *record in allRecords) { + [orphanedObjectIDs addObject:[record objectID]]; + } + + for (NSManagedObjectID *objectID in populatedObjectIDs) { + [orphanedObjectIDs removeObject:objectID]; + } + + NSMutableArray *orphanedRecords = [NSMutableArray array]; + + for (NSManagedObjectID *orphanedObjectID in orphanedObjectIDs) { + [orphanedRecords addObject:[context objectWithID:orphanedObjectID]]; + } + + return orphanedRecords; +} + +@end