patternMinor
NSUser defaults cellForRowAtIndexPath
Viewed 0 times
defaultscellforrowatindexpathnsuser
Problem
I have been going back and forth on one certain part of my code. It works, but it doesn't seem right for some reason, as I believe there must be an easier/cleaner way to implement the
In my header file:
In my Implementation file, under cellForRowAtIndexPath:
```
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
{
static NSString *simpleTableIdentifier = @"SimpleTableCell";
SimpleTableCell cell = (SimpleTableCell )[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
////////////////ADD EDIT GEAR ICON TO ACCESSORY CELL VIEW//////////////////
UIImage *settingsImage = [UIImage imageNamed:@"Edit Wheel"];
UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settingsButton setImage:settingsImage forState:UIControlStateNormal];
[settingsButton setFrame:CGRectMake(0, 0, 28.0, 28.0)];
settingsButton.backgroundColor = [UIColor clearColor];
settingsButton.showsTouchWhenHighlighted = YES;
[settingsButton addTarget:self action:@selector(settingsButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = settingsButton;
/////////////DATE FORMATTER/////////////////////////
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterLongStyle;
UILabel dateLabel = (UILabel) [c
NSUserDefaults. All of which are dates. I apologize that the code is so long. A lot of it is repetitive, and I want to learn the correct way to do this.In my header file:
#define UserDefault [NSUserDefaults standardUserDefaults]In my Implementation file, under cellForRowAtIndexPath:
```
//-------------------------------------------------------------------------------------------------------
- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
//-------------------------------------------------------------------------------------------------------
{
static NSString *simpleTableIdentifier = @"SimpleTableCell";
SimpleTableCell cell = (SimpleTableCell )[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
////////////////ADD EDIT GEAR ICON TO ACCESSORY CELL VIEW//////////////////
UIImage *settingsImage = [UIImage imageNamed:@"Edit Wheel"];
UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
[settingsButton setImage:settingsImage forState:UIControlStateNormal];
[settingsButton setFrame:CGRectMake(0, 0, 28.0, 28.0)];
settingsButton.backgroundColor = [UIColor clearColor];
settingsButton.showsTouchWhenHighlighted = YES;
[settingsButton addTarget:self action:@selector(settingsButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryView = settingsButton;
/////////////DATE FORMATTER/////////////////////////
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterLongStyle;
UILabel dateLabel = (UILabel) [c
Solution
#define UserDefault [NSUserDefaults standardUserDefaults]NO!
There's a reason that Apple didn't bring
#define pre-processor macros into the Swift language. Generally speaking, the primary function of these macros is to make debugging more difficult.In almost all cases of macros, you can get the same thing with constants or functions. Both of these allow for better, more accurate syntax highlighting, and they give an indication as to the actual return type (or depending on the macro, the argument types).
So here, if we want to shorten the
standardUserDefaults call down slightly, we can create a function:NSUserDefaults * standardUserDefaults() {
return [NSUserDefaults standardUserDefaults];
}But I don't really know how much value this really has. Honestly, we should probably be calling into user defaults so infrequently that this macro should have relatively little value.
For example, you already have some redundant calls into user defaults in your existing code base, but I'd make the case that we could minimize this further.
If I've read your code correctly, we are storing seven values in user defaults, correct? They're all dates for particular events, correct? So why don't we stick all of these dates into a dictionary which then goes into a single key for user defaults? So now, we only access user defaults when we need to store or retrieve our dictionary of
@"AnniversaryDates".Throughout your code, you have big sections marked of with comments looking something like this:
////////////////ADD EDIT GEAR ICON TO ACCESSORY CELL VIEW//////////////////This is a pretty clear indicator that you're already aware of how to break your method down into smaller methods. All you have to do is simply do it.
But let's be clear... some of these things can and should be in the logic of the
SimpleTableCell class (which probably deserves a better name).I haven't seen the UI, but it seems like our cell has about four UI elements and an action. Well, these UI elements can be set up in the nib. The image for the settings button can be set in the nib. And the action for tapping that button can be tied to the cell. The cell can then forward that tap to whatever by whatever means (a delegate). But importantly, for having a nib, we're doing way, way too much UI work programmatically.
The code for the date formatter doesn't belong in here. I'd make a case for an
NSDateFormatter extension.+ (NSDateFormatter *)anniversaryDateFormatter {
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
formatter.dateStyle = NSDateFormatterLongStyle;
});
return formatter;
}And now when we need it, we're just grabbing it via a simple call:
[NSDateFormatter anniversaryDateFormatter];As for this big
if-else block you have, well... it simply shouldn't exist at all.We should have proper model objects. Something along the lines of this:
@interface Anniversary : NSObject
@property AnniversaryType anniversaryType;
@property NSDate *anniversaryDate;
@property (readonly) NSString *dateOfAnniversaryDescription;
@property (readonly) NSString *daysAgoDescription;
@endWhere
AnniversaryType is an enumeration we define to account for the different types of anniversaries we care about in the app.From here, we simply build out an array of these objects, and use these model objects to set up our cell:
Anniversary *anniversary = anniversaries[indexPath.row];
cell.dateLabel.text = anniversary.dateOfAnniversaryDescription;
cell.daysLeftLabel.text = anniversary.daysAgoDescription ?: @"Tap Gear Icon To Get Started";And yes... we should either publicly expose these labels in the cell's header, or we should provide methods that allow us to set this text. We absolutely shouldn't be hacking ourselves references to these labels using their tags as you did here:
UILabel *dateLabel = (UILabel*) [cell viewWithTag:100];
UILabel *daysLeftLabel = (UILabel*) [cell viewWithTag:101];To be explicitly clear about how much of your logic should be in the method you've shared with us, if I were writing this, I'd be shooting for something about like this:
```
- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *reuseID = @"SimpleTableCell";
SimpleTableCell cell = (SimpleTableCell )[tableView dequeueReusableCellWithIdentifier:reuseID];
if (!cell) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:reuseID owner:self options:nil];
cell = nib.firstObject;
}
Anniversary *anniversary = anniversaries[indexPath.row];
cell.thumbnail = anniversary.thumbnail;
cell.anniversaryDate = anniversary.dateOfAnniversaryDescription;
cell.daysSinceAnniversary = anniversary.daysAgoDescription ?: @"Tap Gear Icon To Get Started";
Code Snippets
#define UserDefault [NSUserDefaults standardUserDefaults]NSUserDefaults * standardUserDefaults() {
return [NSUserDefaults standardUserDefaults];
}////////////////ADD EDIT GEAR ICON TO ACCESSORY CELL VIEW//////////////////+ (NSDateFormatter *)anniversaryDateFormatter {
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [[NSDateFormatter alloc] init];
formatter.dateStyle = NSDateFormatterLongStyle;
});
return formatter;
}[NSDateFormatter anniversaryDateFormatter];Context
StackExchange Code Review Q#116344, answer score: 7
Revisions (0)
No revisions yet.