Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

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

Merged
merged 2 commits into from

3 participants

@JRG-Developer

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
@JRG-Developer JRG-Developer Added missing NSOrderedSet methods (insert, remove, replace, etc) per…
… Issue #75 comments.
13a3630
@JRG-Developer 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
@batkuip

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?

@JRG-Developer

@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?

@batkuip

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

@JRG-Developer

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...

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

Fix for Ordered Sets Data Import and KVC Issues #440

@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.

@rentzsch rentzsch merged commit a971c39 into rentzsch:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 19, 2013
  1. @JRG-Developer
Commits on Nov 20, 2013
  1. @JRG-Developer

    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
View
14 templates/machine.h.motemplate
@@ -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$>
View
45 templates/machine.m.motemplate
@@ -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.