Skip to content

Custom setter with error out parameter#564

Open
Krizai wants to merge 4 commits intojsonmodel:masterfrom
Krizai:custom_setter_with_error
Open

Custom setter with error out parameter#564
Krizai wants to merge 4 commits intojsonmodel:masterfrom
Krizai:custom_setter_with_error

Conversation

@Krizai
Copy link
Copy Markdown

@Krizai Krizai commented Feb 9, 2017

Implemented custom possibility to use custom setter with error out parameter

It allows to use another JSONModel initializers inside custom setter and propagate error to the topmost. Like here:


- (void)setIconsWithNSDictionary:(NSDictionary *)dictionary error:(NSError**) error
{
    NSMutableDictionary* icons = [NSMutableDictionary new];
    __block NSError* blockError = nil;
    [dictionary enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        NSError* localError = nil;
        PFEffectImageJS* effectImage = [[PFEffectImageJS alloc] initWithDictionary:obj error:&localError];
        if(localError){
            blockError = localError;
            *stop = YES;
            return;
        }
        icons[key] = effectImage;
    }];
    
    if(error){
        *error = blockError;
    }

    self.icons = icons;
}

@billinghamj
Copy link
Copy Markdown
Member

Ah excellent! :) I have been wanting this for a while - much cleaner than the previous solution. Will review and probably make a couple of tweaks.

@ghost ghost mentioned this pull request Feb 14, 2017
Copy link
Copy Markdown
Member

@billinghamj billinghamj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, have reviewed in detail. Most of the changes are stylistic to fit in with the newer code in the project (I know much of the older code is quite different).

Finally, please add tests for both the old and new use of the setters (with BOOL and void return types), add something to show that the old method is deprecated, and update the readme please

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
if ([self __customSetValue:jsonValue forProperty:property]) {
NSError* customSetErr = nil;
if ([self __customSetValue:jsonValue forProperty:property error:&customSetErr]) {
if((err != nil) && (customSetErr != nil))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update to:

if (err != nil && customSetErr != nil)
  *err = customSetErr;

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
// check for custom setter, than the model doesn't need to do any guessing
// how to read the property's value from JSON
if ([self __customSetValue:jsonValue forProperty:property]) {
NSError* customSetErr = nil;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change to NSError *customSetErr

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you use any formatter tool to take care of formatting. Something like uncrustify?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately not at present, no

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
-(void)__addCustomSetterForName:(NSString*) name
withSuffix:(NSString*) suffix
key:(NSString*) key
toProperty:(JSONModelClassProperty*) p{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change to something more like:

- (void)__addCustomSetterToProperty:(JSONModelClassProperty *)property withValueType:(NSString *)valueType
{
  • all args/params on a single line
  • curly brace on a new line
  • space before pointer asterisks, rather than after
  • no space before variable names
  • more clear variable/param naming
  • avoiding unneeded params

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
p.customSetters[key] = [[JSONModelCustomSetter alloc] initWithValue:setterValue withErrorOutParam:NO];
}

SEL setterWithError = NSSelectorFromString([NSString stringWithFormat:@"set%@With%@:error:", name, suffix]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for the error setter first, then return within the respondsToSelector conditional block

Comment thread JSONModel/JSONModel/JSONModel.m Outdated

#pragma mark - custom transformations
- (BOOL)__customSetValue:(id <NSObject>)value forProperty:(JSONModelClassProperty *)property
- (BOOL)__customSetValue:(id <NSObject>)value forProperty:(JSONModelClassProperty *)property error:(NSError**) error
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space before pointer asterisks

Comment thread JSONModel/JSONModel/JSONModel.m Outdated

if ([self respondsToSelector:setterWithError]){
NSValue* setterValue = [NSValue valueWithBytes:&setterWithError objCType:@encode(SEL)];
p.customSetters[key] = [[JSONModelCustomSetter alloc] initWithValue:setterValue withErrorOutParam:YES];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Init with SEL object directly, not the NSValue

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(NSValue was only used because an NSDictionary cannot hold a value type - e.g. SEL, thus there is no need to use NSValue at all)

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
return NO;

SEL setter = nil;
[customSetter.value getValue:&setter];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull SEL directly from JSONModelCustomSetter property, rather than using an NSValue


@interface JSONModelCustomSetter : NSObject

@property ( nonatomic, readonly, strong) NSValue* value;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to SEL type

@property ( nonatomic, readonly, strong) NSValue* value;
@property ( nonatomic, readonly, assign) BOOL withErrorOutParam;

- (instancetype)initWithValue:(NSValue*)value withErrorOutParam:(BOOL) withErrorOutParam;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to:

- (instancetype)initWithSelector:(SEL)selector;

Determine the presence of the error param based on the selector - don't pass this in

Comment thread JSONModel/JSONModel/JSONModel.m Outdated
if (p.customSetters[key])
return;

SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@With%@:", name, suffix]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move all this logic into JSONModelCustomSetter - probably something like:

JSONModelCustomSetter *setter = [JSONModelCustomSetter setterForObj:self propertyName:name valueType:suffix];

if (setter)
  p.customSetters[key] = setter;

Copy link
Copy Markdown
Author

@Krizai Krizai Feb 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view, anyway, I should first check, does the selector exist, and only then create JSONModelCustomSetter. So I can only hide into the class the magic of wrapping into the NSValue ( which anyway will be removed)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the selector doesn't exist, setterForObj would return nil.

@billinghamj
Copy link
Copy Markdown
Member

Also needs to be rebased

@Krizai Krizai force-pushed the custom_setter_with_error branch from 524b0cb to 13ea1b6 Compare February 23, 2017 20:55
@Krizai
Copy link
Copy Markdown
Author

Krizai commented Feb 25, 2017

Do you think old method should be deprecated? I would leave both of them, as in many cases there is no need for error processing in custom setter.

@Krizai
Copy link
Copy Markdown
Author

Krizai commented Feb 25, 2017

Please check new update

@billinghamj
Copy link
Copy Markdown
Member

Yes the old method should be deprecated - we avoid supporting more than one way of doing a given thing at once generally, as it keeps it more maintainable.

@Krizai
Copy link
Copy Markdown
Author

Krizai commented May 6, 2017

Added the warning about deprecation of the old method

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

Successfully merging this pull request may close these issues.

2 participants