Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added missing NSOrderedSet methods (insert, remove, replace, etc) #181

Merged
merged 2 commits into from

3 participants

Joshua Greene Thomas van der Heijden Jonathan 'Wolf' Rentzsch
Joshua Greene

Added missing NSOrderedSet methods (insert, remove, replace, etc):

See Issue #75, comment by @batkuip "Those methods are trickier to implement because the mutable set accessor uses mutableSetValueForKey which seems to call the insertObject:atIndex internally causing it loop forever."

This code creates a temporary mutable set using the ordered set (not the mutable set which loops as noted), making sure to call appropriate KVC methods.

Credit for original code/idea goes to Dmitry Makarenkoless and JLust on StackOverFlow (http://stackoverflow.com/questions/7385439/exception-thrown-in-nsorderedset-generated-accessors).

JRG-Developer added some commits
Joshua Greene JRG-Developer Added missing NSOrderedSet methods (insert, remove, replace, etc) per…
… Issue #75 comments.
13a3630
Joshua Greene JRG-Developer Fixed issues in previous code.
See Issue #75, comment by @batkuip "Those methods are trickier to implement because the mutable set accessor uses mutableSetValueForKey which seems to call the insertObject:atIndex internally causing it loop forever."

This code creates a temporary mutable set using the ordered set (not the mutable set which loops as noted), making sure to call appropriate KVC methods.

Credit for original code/idea goes to @Dmitry Makarenkoless and @JLust on StackOverFlow (http://stackoverflow.com/questions/7385439/exception-thrown-in-nsorderedset-generated-accessors).
a971c39
Thomas van der Heijden

Cool. I'll check it out when I get home. I think I tried the SO fix you are referencing and it works but it didn't send the right notifications making it impractical for use with tableviews etc.. I think this sends out a notification that ALL set items have changed?

Joshua Greene

@batkuip, I believe it should notify observers only about indexes that will be affected.

E.g. from SO code:

- (void)insertObject:(FRPlaylistItem *)value inSubitemsAtIndex:(NSUInteger)idx {

    // Create an indexSet with just the index to be changed
    NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];

    // Notify KVO about upcoming change
    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];

    NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
    [tmpOrderedSet insertObject:value atIndex:idx];    
    [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];

    // Notify KVO about change that occurred
    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}

The other methods have similar KVC calls.

We've been using this in table views (prior to using mogenerator to create the code automatically), and I don't believe any of our apps have issues due to this.

What situation are you envisioning that it would cause a problem?

Thomas van der Heijden

I think I was interested in willChangeValueForKey:withSetMutation:usingObjects: and didChangeValueForKey:withSetMutation:usingObjects: and I couldn't easily recreate them.

Joshua Greene

I don't believe that willChangeValueForKey:withSetMutation:usingObjects: and didChangeValueForKey:withSetMutation:usingObjects: are applicable to NSMutableOrderedSet.

Per my understanding of NSKeyValueObserving Protocol Reference (see here), I believe these methods are only for unordered to-many relationships (i.e. NSMutableSet).

Instead, I believe that willChange:valuesAtIndexes:forKey: and didChange:valuesAtIndexes:forKey: should be used for ordered to-many relationships, which this code does call.

If you find I'm mistaken (I don't believe both are called?), please let me know.

Ideally, Apple would fix this ordered set issue once and for all, but until then, I think this might be the best that can be done...

Joshua Greene JRG-Developer referenced this pull request in magicalpanda/MagicalRecord
Closed

Fix for Ordered Sets Data Import and KVC Issues #440

Jonathan 'Wolf' Rentzsch
Owner

Good news everyone, I just tested this against 10.7 and 10.9 and it works. It will land in mogenerator v1.28, due out Real Soon Now.

Jonathan 'Wolf' Rentzsch rentzsch merged commit a971c39 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 19, 2013
  1. Joshua Greene
Commits on Nov 20, 2013
  1. Joshua Greene

    Fixed issues in previous code.

    JRG-Developer authored
    See Issue #75, comment by @batkuip "Those methods are trickier to implement because the mutable set accessor uses mutableSetValueForKey which seems to call the insertObject:atIndex internally causing it loop forever."
    
    This code creates a temporary mutable set using the ordered set (not the mutable set which loops as noted), making sure to call appropriate KVC methods.
    
    Credit for original code/idea goes to @Dmitry Makarenkoless and @JLust on StackOverFlow (http://stackoverflow.com/questions/7385439/exception-thrown-in-nsorderedset-generated-accessors).
This page is out of date. Refresh to see the latest.
Showing with 57 additions and 2 deletions.
  1. +12 −2 templates/machine.h.motemplate
  2. +45 −0 templates/machine.m.motemplate
14 templates/machine.h.motemplate
View
@@ -115,14 +115,24 @@ extern const struct <$managedObjectClassName$>UserInfo {<$foreach UserInfo userI
<$endif$>
@end
-<$foreach Relationship noninheritedRelationships do$><$if Relationship.isToMany$>
+<$foreach Relationship noninheritedRelationships do$>
+<$if Relationship.isToMany$>
@interface _<$managedObjectClassName$> (<$Relationship.name.initialCapitalString$>CoreDataGeneratedAccessors)
- (void)add<$Relationship.name.initialCapitalString$>:(<$Relationship.immutableCollectionClassName$>*)value_;
- (void)remove<$Relationship.name.initialCapitalString$>:(<$Relationship.immutableCollectionClassName$>*)value_;
- (void)add<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_;
- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_;
+<$if Relationship.isOrdered$>
+- (void)insertObject:(<$Relationship.destinationEntity.managedObjectClassName$>*)value in<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx;
+- (void)removeObjectFrom<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx;
+- (void)insert<$Relationship.name.initialCapitalString$>:(NSArray *)value atIndexes:(NSIndexSet *)indexes;
+- (void)remove<$Relationship.name.initialCapitalString$>AtIndexes:(NSIndexSet *)indexes;
+- (void)replaceObjectIn<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx withObject:(<$Relationship.destinationEntity.managedObjectClassName$>*)value;
+- (void)replace<$Relationship.name.initialCapitalString$>AtIndexes:(NSIndexSet *)indexes with<$Relationship.name.initialCapitalString$>:(NSArray *)values;
+<$endif$>
@end
-<$endif$><$endforeach do$>
+<$endif$>
+<$endforeach do$>
@interface _<$managedObjectClassName$> (CoreDataGeneratedPrimitiveAccessors)
<$foreach Attribute noninheritedAttributesSansType do$>
45 templates/machine.m.motemplate
View
@@ -243,6 +243,51 @@ const struct <$managedObjectClassName$>UserInfo <$managedObjectClassName$>UserIn
- (void)remove<$Relationship.name.initialCapitalString$>Object:(<$Relationship.destinationEntity.managedObjectClassName$>*)value_ {
[self.<$Relationship.name$>Set removeObject:value_];
}
+- (void)insertObject:(<$Relationship.destinationEntity.managedObjectClassName$>*)value in<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx {
+ NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
+ [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet insertObject:value atIndex:idx];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
+- (void)removeObjectFrom<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx {
+ NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
+ [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet removeObjectAtIndex:idx];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
+- (void)insert<$Relationship.name.initialCapitalString$>:(NSArray *)value atIndexes:(NSIndexSet *)indexes {
+ [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet insertObjects:value atIndexes:indexes];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
+- (void)remove<$Relationship.name.initialCapitalString$>AtIndexes:(NSIndexSet *)indexes {
+ [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet removeObjectsAtIndexes:indexes];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
+- (void)replaceObjectIn<$Relationship.name.initialCapitalString$>AtIndex:(NSUInteger)idx withObject:(<$Relationship.immutableCollectionClassName$>*)value {
+ NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
+ [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet replaceObjectAtIndex:idx withObject:value];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
+- (void)replace<$Relationship.name.initialCapitalString$>AtIndexes:(NSIndexSet *)indexes with<$Relationship.name.initialCapitalString$>:(NSArray *)value {
+ [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+ NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self <$Relationship.name$>]];
+ [tmpOrderedSet replaceObjectsAtIndexes:indexes withObjects:value];
+ [self setPrimitiveValue:tmpOrderedSet forKey:@"<$Relationship.name$>"];
+ [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:@"<$Relationship.name$>"];
+}
@end
<$endif$><$endif$><$endforeach do$>
Something went wrong with that request. Please try again.