Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[[ObjectMapper sharedInstance] dictionaryFromObject:object] doesn't work if the object comes from a framework #36

Open
fatuhoku opened this issue Aug 11, 2015 · 9 comments

Comments

@fatuhoku
Copy link

I know that MESRecipePreviewRecipeIngredientViewModel can be converted into a dictionary normally in a standard iOS app project. The moment I moved it to another private pod framework, I saw this error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (MESRecipePreviewRecipeIngredientViewModel)'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000103ccac65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000103963bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x0000000103ccab9d +[NSException raise:format:] + 205
    3   Foundation                          0x00000001035fafd0 _writeJSONValue + 689
    4   Foundation                          0x00000001035ff34d ___writeJSONArray_block_invoke + 130
    5   CoreFoundation                      0x0000000103c14026 __53-[__NSArrayI enumerateObjectsWithOptions:usingBlock:]_block_invoke + 70
    6   CoreFoundation                      0x0000000103c13f5c -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 284
    7   Foundation                          0x00000001035ff262 _writeJSONArray + 264
    8   Foundation                          0x00000001035faf3c _writeJSONValue + 541
    9   Foundation                          0x00000001035ff46f ___writeJSONObject_block_invoke + 220
    10  CoreFoundation                      0x0000000103c3ecd5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
    11  CoreFoundation                      0x0000000103c3ebec -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 236
    12  Foundation                          0x00000001035ff080 _writeJSONObject + 376
    13  Foundation                          0x00000001035faea6 _writeJSONValue + 391
    14  Foundation                          0x00000001035ff46f ___writeJSONObject_block_invoke + 220
    15  CoreFoundation                      0x0000000103c3ecd5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
    16  CoreFoundation                      0x0000000103c3ebec -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 236
    17  Foundation                          0x00000001035ff080 _writeJSONObject + 376
    18  Foundation                          0x00000001035faea6 _writeJSONValue + 391
    19  Foundation                          0x00000001035ff46f ___writeJSONObject_block_invoke + 220
    20  CoreFoundation                      0x0000000103c3ecd5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
    21  CoreFoundation                      0x0000000103c3ebec -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 236
    22  Foundation                          0x00000001035ff080 _writeJSONObject + 376
    23  Foundation                          0x00000001035faea6 _writeJSONValue + 391
    24  Foundation                          0x00000001035ff34d ___writeJSONArray_block_invoke + 130
    25  CoreFoundation                      0x0000000103c14026 __53-[__NSArrayI enumerateObjectsWithOptions:usingBlock:]_block_invoke + 70
    26  CoreFoundation                      0x0000000103c13f5c -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 284
    27  Foundation                          0x00000001035ff262 _writeJSONArray + 264
    28  Foundation                          0x00000001035faf3c _writeJSONValue + 541
    29  Foundation                          0x00000001035ff34d ___writeJSONArray_block_invoke + 130
    30  CoreFoundation                      0x0000000103c14026 __53-[__NSArrayI enumerateObjectsWithOptions:usingBlock:]_block_invoke + 70
    31  CoreFoundation                      0x0000000103c13f5c -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 284
    32  Foundation                          0x00000001035ff262 _writeJSONArray + 264
    33  Foundation                          0x00000001035faf3c _writeJSONValue + 541
    34  Foundation                          0x00000001035ff46f ___writeJSONObject_block_invoke + 220
    35  CoreFoundation                      0x0000000103c3ecd5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
    36  CoreFoundation                      0x0000000103c3ebec -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 236
    37  Foundation                          0x00000001035ff080 _writeJSONObject + 376
    38  Foundation                          0x00000001035faea6 _writeJSONValue + 391
    39  Foundation                          0x00000001035ff34d ___writeJSONArray_block_invoke + 130
    40  CoreFoundation                      0x0000000103c14026 __53-[__NSArrayI enumerateObjectsWithOptions:usingBlock:]_block_invoke + 70
    41  CoreFoundation                      0x0000000103c13f5c -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] + 284
    42  Foundation                          0x00000001035ff262 _writeJSONArray + 264
    43  Foundation                          0x00000001035faf3c _writeJSONValue + 541
    44  Foundation                          0x00000001035facea -[_NSJSONWriter dataWithRootObject:options:error:] + 137
    45  Foundation                          0x00000001035fd76b +[NSJSONSerialization dataWithJSONObject:options:error:] + 345
    46  React                               0x0000000101d2b2ee RCTJSONStringify + 94
    47  React                               0x0000000101c99152 __70-[RCTContextExecutor executeJSCall:method

I.e. I was trying to use OCMapper to convert my ViewModel class into a dictionary that React Native can consume. RN is barfing because the object didn't get converted at all

@aryaxt
Copy link
Owner

aryaxt commented Aug 11, 2015

what do you mean by doesn't work? What's the behavior?

Would it work if you update the code according to this PR? https://github.com/aryaxt/OCMapper/pull/34/files

@fatuhoku
Copy link
Author

@aryaxt Hi aryaxt, thanks for the super quick reply.

Yes I noticed the cause is definitely the bundle checking.

...
    // For example when we are mapping an array of string, we shouldn't try to map the string objects inside the array
    if ([NSBundle mainBundle] != [NSBundle bundleForClass:object.class] && [object class] != [NSArray class])
    {
        return object;
    }

I think the pull request might go some way to fixing it... I'll need to try that.

@fatuhoku
Copy link
Author

@aryaxt I checked out the version from the pull request but it's not helped.

I don't understand why bundle checking is necessary at all. It really shouldn't matter whether the class that I'm trying to convert belongs in one bundle or another — it's just a class, right :S?

Plus, I'm using AppCode, not Xcode. When I debugged the comparison between mainBundlePath and classBundlePath, I found their values were WILDLY different:

mainBundlePath = {__NSCFString * | 0x7ff013d6eb20} "/Users/myusername/Library/Developer/CoreSimulator/Devices/4CCEBA75-D7CE-408F-8135-97927736A940/data/Containers/Bundle/Application/854F84EA-647C-4B99-A94B-E5E94186714B/MakeEatSeeRNUI_Example.app"
classBundlePath = {__NSCFString * | 0x7ff016005020} "/Users/myusername/Library/Caches/AppCode32/DerivedData/MakeEatSeeRNUI-8ccb4a77/Build/Products/Debug-iphonesimulator/MakeEatSeePresenters.framework"

So yeah, there's just no way this comparison could possibly succeed. This causes -dictionaryFromObject:object to fail and return object. Not very useful at all.

@aryaxt
Copy link
Owner

aryaxt commented Aug 11, 2015

yeah the code to detect project-specific classes need to be reworked, right now it only works if the models are in the main bundle

To understand the reason behind that logic, you can pull my code, comment out the code, and run the unit tests. Fell free to open a PR if you find a solution. I'll look into it myself as well

@fatuhoku
Copy link
Author

Hmmm. The relevant test in question is this:

- (void)testShouldMapArrayOfStringFromObjectToDictionary
{
    User *user = [[User alloc] init];
    user.randomKeywords = @[@"keyword1", @2].mutableCopy;

    NSDictionary *dictionary = [self.mapper dictionaryFromObject:user];
    NSArray *array = [dictionary objectForKey:@"randomKeywords"];

    XCTAssertTrue(array.count == 2);
    XCTAssertTrue([array[0] isEqualToString:@"keyword1"]);
    XCTAssertTrue([array[1] isEqualToNumber:@2]);
}

:/ the implementation appears to make quite a lot of assumptions about what classes belong in bundles and which don't. I've got a wild idea: how about check for the NS prefix from the class name instead?

@aryaxt
Copy link
Owner

aryaxt commented Aug 12, 2015

Let me think about the NS prefix, maybe it could be in additions to bundle checking. Bundle checking is very reliable as long as your models are in the main bundle

@fatuhoku
Copy link
Author

@aryaxt Yeah I gave just checking for the NS prefix a quick try, but one of the tests still failed.

@aryaxt
Copy link
Owner

aryaxt commented Aug 24, 2015

@fatuhoku Did you manage to find a solution? I haven't had time to look into this

@fatuhoku
Copy link
Author

@aryaxt Yes — I just used HRCoder + AutoCoding to serialise the JSON out for React Native consumption instead! I'm not sure how they solve the cross-bundle issue. Probably worth checking the HRCoder code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants