If I understand you correctly you ask how to apply DRY (Don't repeat yourself) to this code.
«Two of more — use a for» Edsger W. Dijkstra
or
«Two of more — use an enumeration» vikingosegundo
- (void)viewDidLoad { // or loadView, see Rob's answer
[super viewDidLoad];
NSArray *properties= @[@{@"color": [UIColor orangeColor], @"text": @"Ceterum censeo"},
@{@"color": [UIColor cyanColor], @"text": @"Carthaginem esse"},
@{@"color": [UIColor purpleColor], @"text": @"delendam"}];
[properties enumerateObjectsUsingBlock:^(NSDictionary *properties, NSUInteger idx, BOOL *stop) {
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(0, (idx + 1) * 20, 200, 20)];
l.backgroundColor = properties[@"color"];
l.text = properties[@"text"];
l.font= [UIFont italicSystemFontOfSize:12];
[self.view addSubview:l];
}];
}
Ok, why do I prefer this block-based enumeration here?
Because it has an mutation guard and gives me the correct index for free that I need for the frame.
A C for
-loop for (int idx = 0; idx < [properties count]; ++idx)
gives me the correct index but I must include an extra statement to get the object NSDictionary *property = properties[idx];
and as it has no mutation guard: it could be changed during iteration which might lead to bad things.
A fast enumeration for(NSDictionary *property in properties)
has such a mutation guard and is even slightly faster enumerating than the block enumeration. But it has the big disadvantage that if I need the index, I must call NSUIndex idx = [properties indexForObject:property];
causing a quadratic runtime performance instead of a linear: bye bye, speed advantage. And even worse: if an array contains identical objects it will only find the first one repeatedly — a good chance of creating false data.
Depending on the amount of the code, it might be useful to move this into a helper method — but this is more about taste.
As your question in the end is about readability, I want to share another matter of taste: I like to encapsulate object creation into a distinct scope:
Either by using an implicit block
UILabel *label = ^{
UILabel *l =[[UILabel alloc] initWithFrame:CGRectMake(0, (idx + 1) * 20, 200, 20)];
l.backgroundColor = properties[@"color"];
l.text = properties[@"text"];
l.font= [UIFont italicSystemFontOfSize:12];
return l;
}();
[self.view addSubview:label];
or a statement expression
UILabel *label = ({
UILabel *l =[[UILabel alloc] initWithFrame:CGRectMake(0, (idx + 1) * 20, 200, 20)];
l.backgroundColor = properties[@"color"];
l.text = properties[@"text"];
l.font= [UIFont italicSystemFontOfSize:12];
l;
});
[self.view addSubview:label];