Closed billgarrison closed 11 years ago
I have a model class called MyEvent that subclasses NSObject and implements NSFNanoObjectProtocol.
@interface MyEvent : NSObject <NSFNanoObjectProtocol>
When I attempt to add an instance of that class to an NSFNanoBag, I get the following exception:
2013-04-12 20:48:56.693 NanoStoreDemo[793:11303] -[MyEvent dictionaryRepresentation]: unrecognized selector sent to instance 0x758d3e0 (lldb) po 0x0758d3e0 $2 = 123261920 (lldb) po stacktrace * thread #1: tid = 0x1f03, 0x011f9e52 libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 1.1 frame #0: 0x011f9e52 libobjc.A.dylib`objc_exception_throw frame #1: 0x021774bd CoreFoundation`-[NSObject(NSObject) doesNotRecognizeSelector:] + 253 frame #2: 0x020dbbbc CoreFoundation`___forwarding___ + 588 frame #3: 0x020db94e CoreFoundation`_CF_forwarding_prep_0 + 14 frame #4: 0x0000750c NanoStoreDemo`-[NSFNanoBag addObject:error:](self=0x071ca2b0, _cmd=0x0003a0eb, object=0x0758d3e0, outError=0xbfffdbc8) + 428 at NSFNanoBag.m:220 frame #5: 0x00003bea NanoStoreDemo`-[MasterViewController insertNewObject:](self=0x07580b90, _cmd=0x00039ffb, sender=0x071bb770) + 522 at MasterViewController.m:109 frame #6: 0x0120d705 libobjc.A.dylib`-[NSObject performSelector:withObject:withObject:] + 77 frame #7: 0x001412c0 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96 frame #8: 0x0037da64 UIKit`-[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139 frame #9: 0x0120d705 libobjc.A.dylib`-[NSObject performSelector:withObject:withObject:] + 77 frame #10: 0x001412c0 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96 frame #11: 0x00141258 UIKit`-[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61 frame #12: 0x00202021 UIKit`-[UIControl sendAction:to:forEvent:] + 66 frame #13: 0x0020257f UIKit`-[UIControl(Internal) _sendActionsForEvents:withEvent:] + 578 frame #14: 0x002016e8 UIKit`-[UIControl touchesEnded:withEvent:] + 546 frame #15: 0x00170cef UIKit`-[UIWindow _sendTouchesForEvent:] + 846 frame #16: 0x00170f02 UIKit`-[UIWindow sendEvent:] + 273 frame #17: 0x0014ed4a UIKit`-[UIApplication sendEvent:] + 436 frame #18: 0x00140698 UIKit`_UIApplicationHandleEvent + 9874 frame #19: 0x02047df9 GraphicsServices`_PurpleEventCallback + 339 frame #20: 0x02047ad0 GraphicsServices`PurpleEventCallback + 46 frame #21: 0x02061bf5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53 frame #22: 0x02061962 CoreFoundation`__CFRunLoopDoSource1 + 146 frame #23: 0x02092bb6 CoreFoundation`__CFRunLoopRun + 2118 frame #24: 0x02091f44 CoreFoundation`CFRunLoopRunSpecific + 276 frame #25: 0x02091e1b CoreFoundation`CFRunLoopRunInMode + 123 frame #26: 0x020467e3 GraphicsServices`GSEventRunModal + 88 frame #27: 0x02046668 GraphicsServices`GSEventRun + 104 frame #28: 0x0013dffc UIKit`UIApplicationMain + 1211 frame #29: 0x00001eed NanoStoreDemo`main(argc=1, argv=0xbffff27c) + 141 at main.m:16
Digging into -[NSFNanoBag addObject:error:], it turns out this method is using private NSFNanoObject API to obtain the object's dictionary representation.
- (BOOL)addObject:(id <NSFNanoObjectProtocol>)object error:(out NSError **)outError { ... NSString *objectKey = [(id)object nanoObjectKey]; NSDictionary *info = [(id)object dictionaryRepresentation]; ... }
Rather than using -[NSFNanoObject dictionaryRepresentation], it should be using -[NSFNanoObjectProtocol nanoObjectDictionaryRepresentation].
-[NSFNanoObject dictionaryRepresentation]
-[NSFNanoObjectProtocol nanoObjectDictionaryRepresentation]
- (BOOL)addObject:(id <NSFNanoObjectProtocol>)object error:(out NSError **)outError { ... NSString *objectKey = [object nanoObjectKey]; NSDictionary *info = [object nanoObjectDictionaryRepresentation]; ... }
Here's a unit test for NanoStoreBagTests.m that will demonstrate the bug.
NanoStoreBagTests.m
- (void) testBagAddTwoNSObjectsConformingToProtocol { id car1 = [[NanoCarTestClass alloc] initNanoObjectFromDictionaryRepresentation:@{@"kName" : @"XJ-7"} forKey:[NSFNanoEngine stringWithUUID] store:nil]; id car2 = [[NanoCarTestClass alloc] initNanoObjectFromDictionaryRepresentation:@{@"kName" : @"Jupiter 8"} forKey:[NSFNanoEngine stringWithUUID] store:nil]; NSArray *objects = @[car1, car2]; NSFNanoBag *bag = [NSFNanoBag bag]; NSError *outError = nil; BOOL success = [bag addObjectsFromArray:objects error:&outError]; BOOL hasUnsavedChanges = bag.hasUnsavedChanges; NSDictionary *info = [bag nanoObjectDictionaryRepresentation]; NSArray *returnedKeys = [info objectForKey:NSF_Private_NSFNanoBag_NSFObjectKeys]; STAssertTrue (success, @"expected bag to have saved"); STAssertTrue (hasUnsavedChanges, @"expected bag to have no unsaved changes"); STAssertNil (outError, @"expect bag to return no error on save"); STAssertEquals ([returnedKeys count], [objects count], @"expected saved bag to return %d object keys", [objects count]); }
I have a model class called MyEvent that subclasses NSObject and implements NSFNanoObjectProtocol.
When I attempt to add an instance of that class to an NSFNanoBag, I get the following exception:
Digging into -[NSFNanoBag addObject:error:], it turns out this method is using private NSFNanoObject API to obtain the object's dictionary representation.
Rather than using
-[NSFNanoObject dictionaryRepresentation]
, it should be using-[NSFNanoObjectProtocol nanoObjectDictionaryRepresentation]
.Here's a unit test for
NanoStoreBagTests.m
that will demonstrate the bug.