7
\$\begingroup\$

I will start by explaining the situation and then show some code. I have an app that has an array of "default" settings to display on a user's dashboard. The user can modify these settings to enable or disable certain items that appear on their dashboard.

I want to be able to update the "default" settings and if I add a new item then it will automatically update the user's settings as well, but without overwriting their personal enable/disable setting.

I have this array of dictionaries, the "default":

dashboardItems = @[
                   @{
                       @"id" : @"1",
                       @"order" : @"0",
                       @"title" : @"Steps Traveled",
                       @"unit" : @"",
                       @"type" : HKQuantityTypeIdentifierStepCount,
                       @"sampleUnit" : @"count",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"2",
                       @"order" : @"1",
                       @"title" : @"Flights Climbed",
                       @"unit" : @"",
                       @"type" : HKQuantityTypeIdentifierFlightsClimbed,
                       @"sampleUnit" : @"count",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"3",
                       @"order" : @"2",
                       @"title" : @"Distance Traveled",
                       @"unit" : @"mi",
                       @"type" : HKQuantityTypeIdentifierDistanceWalkingRunning,
                       @"sampleUnit" : @"mi",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"4",
                       @"order" : @"3",
                       @"title" : @"Active Calories",
                       @"unit" : @"",
                       @"type" : HKQuantityTypeIdentifierActiveEnergyBurned,
                       @"sampleUnit" : @"kcal",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"5",
                       @"order" : @"4",
                       @"title" : @"Weight",
                       @"unit" : @"lbs",
                       @"type" : HKQuantityTypeIdentifierBodyMass,
                       @"sampleUnit" : @"lb",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"6",
                       @"order" : @"5",
                       @"title" : @"Cycling",
                       @"unit" : @"mi",
                       @"type" : HKQuantityTypeIdentifierDistanceCycling,
                       @"sampleUnit" : @"mi",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"7",
                       @"order" : @"6",
                       @"title" : @"Heart Rate",
                       @"unit" : @"BPM",
                       @"type" : HKQuantityTypeIdentifierHeartRate,
                       @"sampleUnit" : @"count/min",
                       @"enabled" : @"1"
                   },
                   @{
                       @"id" : @"8",
                       @"order" : @"7",
                       @"title" : @"BMI",
                       @"unit" : @"",
                       @"type" : HKQuantityTypeIdentifierBodyMassIndex,
                       @"sampleUnit" : @"count",
                       @"enabled" : @"1"
                   }
        ];

So the user can use a switch to change the enabled from a 1 to a 0 or vice-versa to turn on or off the item, with me so far?

When the user signs up the app saves the "default" settings to NSUserDefaults and also to the live server to backup in case the user ever deletes the app.

If the user logs out or deletes the app, on next login we check to see if they currently have and NSUserDefaults saved, if not we pull from the server.

Then I compare the 2 arrays to see if any items were changed or added to the "defaults", is this the best way to go about doing it?

//here we need to check if the user does not have any preferences saved, if not pull them from Parse.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSMutableArray *dashboardItems = [defaults objectForKey:@"dashboardItems"];

if (dashboardItems == nil) {

    //user has no preferences so load them in
    dashboardItems = [NSJSONSerialization JSONObjectWithData:[user[@"preferences"] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];

    [defaults setObject:dashboardItems forKey:@"dashboardItems"];
    [defaults synchronize];

}

//compare current preferences against default to see if any new items were changed
NSArray *defaultPreferences = [[PreferencesManager sharedManager] dashboardItems];

for (NSDictionary *item in defaultPreferences) {

    for (NSDictionary *userItem in dashboardItems) {

        if ([item[@"id"] isEqualToString:userItem[@"id"]]) {

            //we have a match, compare name and change if necessary
            if (![item[@"title"] isEqualToString:userItem[@"title"]]) {

                //set user's item title to default title
                [userItem setValue:item[@"title"] forKey:@"title"];

            }

        } else {

            //we did not find this in user preferences, so add it
            [dashboardItems addObject:item];

        }

    }


}

//save defaults
[defaults setObject:dashboardItems forKey:@"dashboardItems"];
[defaults synchronize];
\$\endgroup\$

1 Answer 1

7
\$\begingroup\$
//we have a match, compare name and change if necessary
if (![item[@"title"] isEqualToString:userItem[@"title"]]) {

    //set user's item title to default title
    [userItem setValue:item[@"title"] forKey:@"title"];

}

This sort of code is a bit redundant, and also shows inconsistency between using and not using the modern syntax for dictionaries.

We can rewrite it as simply:

userItem[@"title"] = item[@"title"];

We don't need to check whether or not they're different titles.


The amount of vertical white space in your code is excessive and distracting. We can eliminate most of these empty lines. I don't think they add anything other than making me work my scroll wheel a bit more.


Calling synchronize on NSUserDefaults is largely unnecessary. NSUserDefaults loads the defaults into memory. When you set a value, it sets it in memory (but doesn't save it to permanent storage yet). Next time you access the value for that key, it will serve you the value you set (which it has in memory), regardless of whether or not it has taken the time to write it to permanent storage yet or not.

NSUserDefaults tries to find opportune, low-cost times to write to permanent storage when it knows it has pending changes. Worst case scenario, it will be sure to write to permanent storage just before your app is exited.

The only way to lose something that is in NSUserDefaults in memory but not yet written to permanent storage is if your app crashes without NSUserDefaults having an opportunity to write.

All that calling synchronize does is make your app take the time to force NSUserDefaults to write its current state to permanent storage. That's it. It's completely unnecessary, and your app shouldn't be crashing and losing its temporary storage stuff anyway.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much for all of your comments. It definitely makes sense that I don't need to check whether or not they're different, just always overwrite it. I wasn't aware that you didn't need to call synchronize I will keep that in mind from now on. Again, thanks for your help. \$\endgroup\$ May 8, 2015 at 15:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.