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

Manual setting of mapping provider to return currentNode is needed to prevent empty fetched data from JSON #55

Closed
haxpor opened this Issue Aug 1, 2016 · 7 comments

Comments

Projects
None yet
2 participants
@haxpor
Copy link

haxpor commented Aug 1, 2016

I have 2 model classes

@interface PBQuiz : NSObject <OCMapperConfigurable>

@property (nonatomic, strong) NSString* name;
@property (nonatomic, strong) NSString* image;
@property (nonatomic, strong) NSNumber* weight;
@property (nonatomic, strong) NSArray<NSString*>* tags;
@property (nonatomic, strong) NSString* desc;
@property (nonatomic, strong) NSString* descriptionImage;
@property (nonatomic, strong) NSString* quizId;

@end

and

@interface PBQuizDetail : PBQuiz <OCMapperConfigurable>

@property (nonatomic, strong) NSDate* dateStart;
@property (nonatomic, strong) NSDate* dateExpire;
@property (nonatomic, strong) PBQuizType* type;
@property (nonatomic, strong) NSArray<PBQuizGrade*>* quizGrades;
@property (nonatomic, strong) NSNumber* status;
@property (nonatomic, strong) NSNumber* questionOrder;
@property (nonatomic, strong) NSNumber* deleted;
@property (nonatomic, strong) NSNumber* totalMaxScore;
@property (nonatomic, strong) NSNumber* totalQuestions;
@property (nonatomic, strong) NSNumber* questions;
@property (nonatomic, strong) NSNumber* totalScore;
@property (nonatomic, strong) NSDate* dateJoin;

@end

I have to manually add the following code

[mappingProvider mapFromDictionaryKey:@"grades" toPropertyKey:@"grades" forClass:[PBQuizDetail class] withTransformer:^id(id currentNode, id parentNode) {
        return currentNode;
    }];

just to return currentNode in order to receive value from JSON. If I didn't do this, I will always get 0 elements. Interesting thing also is that it's marked as JKArray type when I see it in debugger. I also use JSONKit. I'm not sure if OCMapper is conflict with JSONKit and cause this issue.

Note, OCMapperConfigurable is just protocol I use which has no effect of this issue.

@haxpor haxpor changed the title Property name cannot be `grades` to deserialize data from JSON Manual setting of mapping provider to return currentNode is needed to prevent empty fetched data from JSON Aug 1, 2016

@haxpor

This comment has been minimized.

Copy link
Author

haxpor commented Aug 1, 2016

I just realize manually set mapping provider and return currentNode will get us NSDictionary as type.

I have remove JSONKit, and the problem still exists.

@aryaxt

This comment has been minimized.

Copy link
Owner

aryaxt commented Aug 1, 2016

hmm you are mapping from a dictionary key named grades does that key exist in the data?
you are mapping it to a property named "grades" on the object of type PBQuizDetail, but that class doesn't have a property named "grades".

What exactly are you trying to map?

If you are trying to map an array of grades to quizGrades you can do

[inCodeMappingProvider mapFromDictionaryKey:@"KEY_FROM_DICTIONARY" toPropertyKey:@"quizGrades" withObjectType:PBQuizGrade.class forClass:PBQuizDetail.class];
// replace KEY_FROM_DICTIONARY with the name of the key in your dictionary
@haxpor

This comment has been minimized.

Copy link
Author

haxpor commented Aug 2, 2016

@aryaxt Thanks. I got it working by using your suggestion. Actually, what I want to do is not to map anything to anything. JSON data is there, but it didn't deserialize into model object. It's weird that I have to use your suggestion to manually tell model object class to map the field in which normally it will do that automatically.

That issue starts with

@property (nonatomic, strong) NSArray<PBQuizGrade*>* quizGrades in QuizDetail class.

then it also goes for NSArray property nested inside PBQuizGrade. It goes like this in chain.

I suspect something.
In PBQuiz class, there's a JSON field description. I mapped it to property desc because it will be conflicting with description method. It works fine, but now I have PBQuizDetail class which extends PBQuiz, if I didn't map description to desc for PBQuizDetail class (not PBQuiz class). The crash will show as follows.

2016-08-02 09:32:50.377 xctest[28900:3636605] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<PBQuizDetail 0x7fc947724e90> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key description.'

So I have to do that to avoid crash. I suspect that this might be the root cause that I have to manually map those arrays.

@haxpor

This comment has been minimized.

Copy link
Author

haxpor commented Aug 2, 2016

I think this is because the automatic mapping that tries to map singular noun class from plural noun in NSArray type of data. Thus it cannot find the proper class, and I have to manually tell it.

Could this be automatic process as I always provide the type of element something like this NSArray<MyObject*>*?

@aryaxt

This comment has been minimized.

Copy link
Owner

aryaxt commented Aug 2, 2016

Could this be automatic process as I always provide the type of element something like this NSArray<MyObject*>*?

Unfortunately no it can't be done

The reason is objective c runtime-api doesn't provide info about the types of objects in an array, the way it works automatically in some cases is by using property names to try to find a matching class. in this case you don't have a matching property/class name and dictionary key. That's why it has to be done manually

What OCMapper does for trying to map arrays is to check for the key in dictionary. For example in this case your dictionary-key is quizGrades so OCMapper looks for a class named QuizGrades or QuizGrade, if the class exists it for mapping otherwise it'll ignore it

@haxpor

This comment has been minimized.

Copy link
Author

haxpor commented Aug 5, 2016

Hey thanks so much much for explanation. It would be real useful but too bad the runtime doesn't support. Most of the time I have model class that has prefix naming, but definitely json field naming doesn't include prefix.

Ok, so for this case do you think it's better to close this issue or leave it as improvement later (not sure if there's a chance for it to support?).

@aryaxt

This comment has been minimized.

Copy link
Owner

aryaxt commented Aug 5, 2016

You're welcome :)
I think I'll close this since it's really not a supported feature of objective c

NOTE: This behavior is only for collections (array, set, etc), for non collection properties the type of objects can be determined at runtime, and they will be mapped automatically as long as dictionary key is named the same a property name

🍻

@aryaxt aryaxt closed this Aug 5, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment