0

I have a function that gives 2 different String values that are returned :

-(NSString*)load:(NSDictionary *)dict
{

    NSDictionary *dataDict = [self objectForId:@"data" fromDict:dict withDefault:nil];
    if (dataDict) {
        NSDictionary *success = [self objectForId:@"success" fromDict:dataDict withDefault:nil];

        NSString *str = [NSString stringWithFormat:@"%@", success];

        if ([str isEqualToString: @"1"])
        {
            NSDictionary *idDict = [self objectForId:@"id" fromDict:dataDict withDefault:nil];
            if (idDict) {
                NSString *idString = [NSString stringWithFormat:@"%@", idDict];
                return idString;
            }

        } else {
            NSDictionary *messages = [self objectForId:@"messages" fromDict:dataDict withDefault:nil];
            if (messages) {
                NSDictionary *messageDict = (NSDictionary *)messages;
                NSArray *type = messageDict[@"type"];
                if (type.count > 0) {
                    NSString *messageString = type[0][@"message"];
                    return messageString;
                }
            }
        }
    }
    return  nil;
}

And accessing the stringValue like this :

 NSString *string = [className load:dict];

Now I want to write if else statements for "idString" and "messageString" return values. How do I differentiate the 2 return values?

user1285402
  • 143
  • 2
  • 12
  • 1
    You want to know on the line `NSString *string = [className load:dict];`, if `string` comes from the success or "id" or the "messages" key? What about using a block for that? Or returning a dictionary? or using two pointers of points (`-(void)load:(NSDictionary *) dict key:(NSString **)key value:(NSString **)value`), and call it with `[className load:dict key:&someString value:&string]`? – Larme Jul 02 '18 at 10:23
  • @Larme How to use a completion block to return the value? – user1285402 Jul 03 '18 at 19:44

5 Answers5

1

While returning a NSDictionary (see @Yihui Yang solution), or a custom Class (see @Sulthan's solution) for it are valid solutions, it maybe be too much.
You need to remember the keys of the dictionary returned, or maybe creating a custom class just for that is too much.

Here are two other possibilities:

I'll have has sample dict to test:

NSDictionary *dictToTest1 = @{@"id": @"idString",
                              @"noiseKey": @"noiseValue"
                              };
NSDictionary *dictToTest2 = @{@"messages": @"messagesString",
                              @"noiseKey": @"noiseValue"
                              };

I'll simplify your test to check only if there is a key/value for key id or for messages.

Using Double pointers:

-(void)loadDict:(NSDictionary *)dict withRetKey:(NSString **)key andRetValue:(NSString **)value
{
    NSString *retKey = nil;
    NSString *retValue = nil;
    if (dict[@"id"])
    {
        retKey = @"id";
        retValue = dict[@"id"];
    }
    else if (dict[@"messages"])
    {
        retKey = @"messages";
        retValue = dict[@"messages"];
    }

    if (key)
    {
        *key = retKey;
    }

    if (value)
    {
        *value = retValue;
    }
}

Sample test:

NSString *key1 = nil;
NSString *value1 = nil;
[self loadDict:dictToTest1 withRetKey:&key1 andRetValue:&value1];
NSLog(@"Key1: %@\t value1: %@", key1, value1);
NSString *key2 = nil;
NSString *value2 = nil;
[self loadDict:dictToTest2 withRetKey:&key2 andRetValue:&value2];
NSLog(@"Key2: %@\t value2: %@", key2, value2);

Output:

$> Key1: id  value1: idString
$> Key2: messages    value2: messagesString

Where did you see the & for objects ?
Almost all the times in managing a NSError. (linked question)
For primitive? For sample if you want to retrieve the red/blue/green/alpha of a UIColor (linked question)

With blocks:

-(void)blockLoadDict:(NSDictionary *)dict withBlock:(void(^) (NSString *key, NSString *value))block
{
    NSString *retKey = @"";
    NSString *retValue = @"";
    if (dict[@"id"])
    {
        retKey = @"id";
        retValue = dict[@"id"];
    }
    else if (dict[@"messages"])
    {
        retKey = @"messages";
        retValue = dict[@"messages"];
    }

    if (block)
    {
        block(retKey, retValue);
    }
}

Sample:

__block NSString *key3 = nil;
__block NSString *value3 = nil;
[self blockLoadDict:dictToTest1 withBlock:^(NSString *key, NSString *value) {
    key3 = key;
    value3 = value;
}];
NSLog(@"Block Key3: %@\t value3: %@", key3, value3);

__block NSString *key4 = nil;
__block NSString *value4 = nil;
[self blockLoadDict:dictToTest2 withBlock:^(NSString *key, NSString *value) {
    key4 = key;
    value4 = value;
}];
NSLog(@"Block Key4: %@\t value4: %@", key4, value4);

Output:

$> Block Key3: id    value3: idString
$> Block Key4: messages  value4: messagesString
Larme
  • 24,190
  • 6
  • 51
  • 81
0

What I understand is that you want to know if load method returns an idString or messageString.

So what I recommend is using a tricky method.

Instead of return a string, you can return a dict which is like

    return @{
         @"type":@"idString",
         @"content":idString
         }

And using

NSDictionary * returnDict = [className load:dict]
if ([returnDict[@"type"] isEqualToString:@"idString"]) {
    //code here
}
else{
    //code here
}

Finally, I know this is not a best solution but it will work fine.

Tamashii
  • 49
  • 2
  • 5
0

I'd make 2 separate methods. First would only return the id string, the second one would return a message.

That way you can make something like this:

NSDictionary *dict = /* some code here */;
NSString *message = nil;
NSString *idString = [foo loadId:dict];
if (idString.length == 0) {
    message = [foo loadMessage:dict];
}
dosi
  • 476
  • 5
  • 10
0

Instead of returning a simple string, create an object that will be returned:

@interface Result: NSObject
@property (nonatomic) NSString *id;
@property (nonatomic) NSString *message;
@end

Ideally, you could create -initWithDictionary: initializer that would handle the parsing.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
-1

You can use NSException. Instead of returning idString you throw an NSException

@throw [NSException exceptionWithName:idString reason:nil userInfo:nil];

Then you can call your method like this:

@try{
    NSString *messageString = [className load:dict];
    NSLog(@"Message String: %@", messageString);
}@catch (NSException *e){
    NSString * idString = e.name;
    NSLog(@"ID String: %@",idString);
}
  • 1
    This is a really bad idea. Exceptions in Objective-C are very expensive. They should only be used for actual exceptions. It should not be used to differentiate data in a return value. – rmaddy Jun 29 '18 at 18:55
  • In know exceptions are expensive but I cannot thing of any other way to do it and keep the method returning NSString. Maybe if there is some pattern how id strings is different from messages string you can check the string. For example checking if string is contains n numbers but again message string can be composed in same way – najdanovicivan Jul 03 '18 at 09:45
  • @najdanovicivan You can have a look at my answer if you want. I linked also with two others answers listing then 4 ways of doing so. They don't "directly" return `NSString` (meaning it's not `-(NSString *)method`), but they are other ways... – Larme Jul 06 '18 at 11:12
  • The answer you put is the most similar to how will I do it. But I'll use bool value for retKey since there are only two possible values there. I just answered how to keep the -(NSString *)method. I know exceptions are expensive. But I just don see any other way to do it and keep the method unchanged – najdanovicivan Jul 08 '18 at 07:13