3

I have this initializer for an object:

-(id)init
{
    self = [super init];
    if (self) {
        if([[NSUserDefaults standardUserDefaults] objectForKey:kTermsAccepted] != nil){
            _termsAccepted = [[NSUserDefaults standardUserDefaults] boolForKey:kTermsAccepted];
        }
        if([[NSUserDefaults standardUserDefaults] objectForKey:kInitialSetupCompleted] != nil){
            _initialSetupCompleted = [[NSUserDefaults standardUserDefaults] boolForKey:kInitialSetupCompleted];
        }
        if([[NSUserDefaults standardUserDefaults] objectForKey:kDashboardMessage] != nil){
            _dashboardMessage = [[NSUserDefaults standardUserDefaults] objectForKey:kDashboardMessage];
        } else{
            _dashboardMessage = [[NSBundle mainBundle] localizedStringForKey:kDMDefaultDashboardMessage value:kDMDefaultDashboardMessage table:nil];
        }
        //50 other if statements
    }
    return self;
}

What would be a better way to do this so I don't get these warnings while doing an OCLint analysis?

Thanks!

Jan
  • 2,462
  • 3
  • 31
  • 56

1 Answers1

5

All instance variables are initialised to 0; that means that BOOLs are initialised to NO. Therefore the effect of:

if([[NSUserDefaults standardUserDefaults] objectForKey:kTermsAccepted] != nil){
    _termsAccepted = [[NSUserDefaults standardUserDefaults] boolForKey:kTermsAccepted];
}

... is: if there is a stored value then set _termsAccepted to it. Otherwise _termsAccepted will be NO.

boolForKey: has a documented return value of:

If a boolean value is associated with defaultName in the user defaults, that value is returned. Otherwise, NO is returned.

So compare and contrast with just:

_termsAccepted = [[NSUserDefaults standardUserDefaults] boolForKey:kTermsAccepted];

... in that case the net result will be: if there is a stored value then set _termsAccepted to it. Otherwise _termsAccepted will be NO.

So to reduce cyclomatic complexity, drop the if statements. They add nothing.

EDIT: it's been correctly pointed out that I've missed the fact that BOOLs are not exclusively in use.

Use -[NSUserDefaults registerDefaults:] to establish your fallback values. Those are kept in memory once set but not written to the store. Then the user defaults themselves will handle the "if no value stored, use this value" case for all types of object.

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • Ok, maybe my question wasn't clear. Or maybe it is. But where it says "/50 other if statements" there are other types of variables as well, not only BOOLs. I have NSStrings, NSMutableArrays, NSDate, etc. Would the direct assignment work with any kind of type? – Jan Mar 16 '16 at 18:37
  • I actually added one of my situations, where I want to init with a default value in case the NSUserDefaults is not there... – Jan Mar 16 '16 at 18:39
  • 2
    I probably under-read the question. My fault. As edited, try using `-[NSUserDefaults registerDefaults:]` to set the values that NSUserDefaults should return if values aren't found. They never overwrite actually stored information and are themselves never written to the store. It's an in-memory fallback only. – Tommy Mar 16 '16 at 18:42
  • Awesome Tommy, thanks a lot. I'll try this out and come back later to select as accepted if everything works (which I think it should!). Thanks – Jan Mar 16 '16 at 18:43
  • 1
    I second the recommendation to use `registerDefaults:`. I demonstrate an example in this answer: http://stackoverflow.com/a/4530149/277952 – NSGod Mar 16 '16 at 18:48