HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Data model code review for iOS app

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
iosappmodelforcodedatareview

Problem

I'm new to iOS development and I'm having trouble figuring out how to efficiently load my app's data at launch time. My app consists of a UITableView that is populated with a list of songs. Each cell displays data about the song: current user rating(if rated) and avg. user rating (avg. rating of all users). I'm using Parse for my backend data storage.

At launch time, my app runs two queries. The first query fetches songs to populate the table. It then calculates the avg. user rating (my backend schema includes count objects: rating1_count, rating2_count, etc. which are incremented when the user rates a song). It also orders the songs into separate data model arrays: topTracksOfTheWeek, topTracksOfTheMonth, topTracksAllTime.

The second query fetches all of the rated songs by the current user. It then compares this query to the first query to embed the user rating data into the first query to form the app's data model.

I'd like to limit the first query to 50 songs to optimize load time. However, with my current data model, I need to query all of the songs in my database to calculate all of the avg. user ratings and then order the songs into the topTracks arrays.

The only solution I can come up with is running a server-side script periodically to calculate the avg. user ratings. I would have to create a new class in my database for the topTracks arrays that are ordered by the script. In my app, I would do a lazily do a third query for the topTracks arrays.

Here is my data model code:

```
  • (void)getDataSource


{

PFUser *user = [PFUser currentUser];

NSMutableArray *ratings;
if (user) {
PFQuery *queryRatings = [PFQuery queryWithClassName:@"Ratings"];
[queryRatings whereKey: @"user" equalTo: user.username];
[queryRatings orderByDescending:@"createdAt"];
queryRatings.limit = 1000;
ratings = [NSMutableArray arrayWithArray:[queryRatings findObjects]];
}
else
[self displayLoginViewController];

Solution

Consider following scheme -

Each song has a key numberOfRatings and a key averageRating.
Their initial value is 0.

When user rates a song with newRating, you change the value of averageRating according to this formula

averageRating = ((averageRating * numberOfRatings) + newRating) / (numberOfRatings + 1)


And of course you increase numberOfRatings

numberOfRatings = (numberOfRatings + 1)


With this approach you can utilize queries (query only the first 50 songs according to their averageRating etc.) for your topTracks chart views, and you do not have to query all songs just to count their average rating - at any given moment you have an up-to-date averageRating stored for every song.

Code Snippets

averageRating = ((averageRating * numberOfRatings) + newRating) / (numberOfRatings + 1)
numberOfRatings = (numberOfRatings + 1)

Context

StackExchange Code Review Q#15353, answer score: 3

Revisions (0)

No revisions yet.