1

Is there an easier, less copy/paste way of achieving the same thing as the code below? What is the best way?

if (self.title.selectedSegmentIndex !=-1)
{
    [self.form setValue:[self.title titleForSegmentAtIndex:self.title.selectedSegmentIndex] forKey:@"titleKey"];
}
if (self.author.selectedSegmentIndex !=-1)
{
    [self.form setValue:[self.author titleForSegmentAtIndex:self.author.selectedSegmentIndex] forKey:@"authorKey"];
}
if (self.description.selectedSegmentIndex !=-1)
{
    [self.form setValue:[self.description titleForSegmentAtIndex:self.description.selectedSegmentIndex] forKey:@"descriptionKey"];
}
etc....

Edit: sorry its not a bool if statement (I believe I need this check though, otherwise it will crash when no segment is selected when trying to get the title from the index)

I feel like I have a lot of repetitive checking with these if statements and dont know a better way, any suggestions are appreciated.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
BluGeni
  • 3,378
  • 8
  • 36
  • 64
  • Hint: if you've created your properties correctly, you can use `[self valueForKey:@"title"]` instead of `self.title`. Then it could be as simple as looping through an array of keys. – Cyrille Jul 12 '13 at 14:05
  • @Cyrille Exactly, and that way, it would be something like `for (NSString *key in keysArray) { id val = [self valueForKey:key]; if (val) [self.form setValue:val forKey:key]; }` –  Jul 12 '13 at 14:07
  • 1
    @Cyrille Im sorry, what do you mean made my properties correctly? – BluGeni Jul 12 '13 at 14:11
  • this is a way to do it, but idk if it makes it easier or less convoluted NSArray* segmentThingies = @[self.title, self.author, self.description]; NSArray* key = @[@"titleKey", @"authorKey", @"descriptionKey"]; for ( NSInteger i = 0; i < [segmentThingies count]; i++ ) { UISegmentedControl* segment = (UISegmentedControl*)[segmentThingies objectAtIndex:i] selectedSegmentIndex]; NSString* keyString = [key objectAtIndex:i]; if ([segment selectedSegmentIndex] != -1) { [self.form setValue:[segment titleForSegmentAtIndex:segment.selectSegmentIndex] forKey:key]; } } – A'sa Dickens Jul 12 '13 at 14:31
  • might be better if you copy paste that x.x didn't think it was that long – A'sa Dickens Jul 12 '13 at 14:31
  • it might also be better if you put it as an answer so I could actually read it and accept it :) – BluGeni Jul 12 '13 at 14:35

2 Answers2

4

There are several approaches to this kind of thing. (None of the code here has been tested or even compiled.)

The most obvious is a simple method:

- (void)setFormValueFromSegmentedControl:(UISegmentedControl *)seg forKey:(NSString *)key {
  if (seg.selectedSegmentIndex !=-1) {
    [self.form setValue:[seg titleForSegmentAtIndex:seg.selectedSegmentIndex] forKey:key];
  }
}

Now your code simplifies to:

[self setFormValueFromSegmentedControl:self.title forKey:@"titleKey"];
[self setFormValueFromSegmentedControl:self.author forKey:@"authorKey"];
...

Personally, I like this because it's so simple and obvious to read with a minimum of magic. But there are other solutions if even that block got unwieldy.

You can do something like @Cyrille and @H2CO3 are suggesting:

for (NSString *key in [@"title", @"author", ...]) {
  UISegmentedControl *seg = [self valueForKey:key];
  if (seg.selectedSegmentIndex != -1) {
    NSString *formKey = [key stringByAppendingString:@"Key"];
    [self.form setValue:[seg titleForSegmentAtIndex:seg.selectedSegmentIndex] forKey:formKey];
  }
}

You could also use a tag on the control to indicate which form key it applies to (you can configure tags in IB or using setTag: in code). So title would have a tag of 0, author would have a tag of 1, etc.

NSArray *formKeyForTag = @[@"titleKey", @"authorKey", ...];
for (UISegmentedControl *seg = [... IBOutletCollection of controls ...]) {
  if (seg.selectedSegmentIndex != -1) {
    NSString *formKey = formKeyForTag[seg.tag];
    [self.form setValue:[seg titleForSegmentAtIndex:seg.selectedSegmentIndex] forKey:formKey];
  }

Or you could add an associated object to the segmented control, pointing to the form key. See What is objc_setAssociatedObject() and in what cases should it be used? for more on that. (I happen to love associated objects…)

Or you could use an NSDictionary to keep the mappings.

So lots of options. But I kind of like the simple method at the top. It's the most obvious.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
0
@protocol ObjectsWithSegmentAtIndex <NSObject>

@property (assign, atomic) NSInteger selectedSegmentIndex;

@end

.h

@interface BaseClass : NSObject    
@property (assign, atomic) id<ObjectsWithSegmentAtIndex> title;
@property (assign, atomic) id<ObjectsWithSegmentAtIndex> description;
...
@property (assign, atomic) Form* form;
@end

.m

NSString* KeyForValue (id<ObjectsWithSegmentAtIndex> value) {
    return [value description]; // example, not to be used this way
}

+(void) fillForm:(Form*)form withValues:(NSArray*) values {
    for (id<ObjectsWithSegmentAtIndex> value in values) {
        [self fillForm:form withValue:value forKey:KeyForValue(value)];
    }
}

+(void) fillForm:(Form*)form withValue:(id<ObjectsWithSegmentAtIndex>)value forKey:(id<NSCopying>)key {
    if (value.selectedSegmentIndex != kUndefinedSegmentIndex) {
        [form setValue:[value titleForSegmentAtIndex:value.selectedSegmentIndex] forKey:key];
    }
}
A-Live
  • 8,904
  • 2
  • 39
  • 74