Reputation: 319
I am new to iOS programming and I need some advice. I want to create a table view with sections to learn how it works. I have some objects from a model class user
. I fill data in the table view using dictionaries. The table view is in a view Controller in my storyboard. The code works, but I don't know if this is a good way to handle the data in my table. Is this a semantic mistake to do this like I did?
Please take a Look at my code and give me some advice.
My user object (User.h
):
@interface User : NSObject
@property (nonatomic, strong) NSString *email;
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@property (nonatomic, strong) NSString *city;
@end
Dummy function to fill users into an array (in a helper class):
- (NSMutableArray *) createUser
{
NSMutableArray *userArray = [[NSMutableArray alloc] init];
User *user1 = [[User alloc] init];
user1.firstName = @"Donald";
user1.lastName = @"Duck";
user1.email = @"[email protected]";
user1.city = @"Entenhausen";
User *user2 = [[User alloc] init];
user2.firstName = @"Micky";
user2.lastName = @"Maus";
user2.email = @"[email protected]";
user2.city = @"Entenhausen";
User *user3 = [[User alloc] init];
user3.firstName = @"Daisy";
user3.lastName = @"Duck";
user3.email = @"[email protected]";
user3.city = @"Frankfurt";
User *user4 = [[User alloc] init];
user4.firstName = @"Goofy";
user4.lastName = @"Goof";
user4.email = @"[email protected]";
user4.city = @"Berlin";
User *user5 = [[User alloc] init];
user5.firstName = @"Some";
user5.lastName = @"Body";
user5.email = @"[email protected]";
user5.city = @"Somewhere";
User *user6 = [[User alloc] init];
user6.firstName = @"Dagobert";
user6.lastName = @"Duck";
user6.email = @"[email protected]";
user6.city = @"Mainz";
[userArray addObject:user1];
[userArray addObject:user2];
[userArray addObject:user3];
[userArray addObject:user4];
[userArray addObject:user5];
[userArray addObject:user6];
return userArray;
}
Function to create a dictionary object (in a helper class):
- (NSMutableDictionary *) createDictionaryFromArray: (NSMutableArray *) allData
{
NSArray *arrayKeys = [[NSArray alloc] initWithObjects:@"Entenhausen", @"Frankfurt", @"Berlin", @"Mainz", nil];
NSMutableDictionary *collection = [[NSMutableDictionary alloc] init];
for (int i=0; i < arrayKeys.count; i++) {
NSString *key = [arrayKeys objectAtIndex:i];
NSMutableArray *allValues = [[NSMutableArray alloc] init];
for (User *usr in allData) {
if([usr.city isEqualToString:key]) {
[allValues addObject:usr];
}
}
[collection setObject:allValues forKey:key];
}
return collection;
}
My table view controller class (TableViewController.h
):
#import <UIKit/UIKit.h>
#import "HelperClass.h"
@interface TableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
HelperClass *helper;
NSMutableArray *users;
NSArray *allKeys;
NSDictionary *dictionaryUsers;
}
TableViewController.m
:
#import "TableViewController.h"
@implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
helper = [[HelperClass alloc] init];
users = [[NSMutableArray alloc] init];
users = [helper createUser];
dictionaryUsers = [[NSMutableDictionary alloc] init];
dictionaryUsers = [helper createDictionaryFromArray:users];
allKeys = [NSArray array];
allKeys = [dictionaryUsers allKeys];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{ // Return the number of sections.
return [allKeys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSMutableArray *arrayValuesUsers = [[NSMutableArray alloc] init];
arrayValuesUsers = [dictionaryUsers objectForKey:[allKeys objectAtIndex:section]];
return [arrayValuesUsers count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [allKeys objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
User *user = [[User alloc] init];
NSMutableArray *usersInSection = [dictionaryUsers objectForKey:[allKeys objectAtIndex:indexPath.section]];
user = [usersInSection objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@, %@", user.lastName, user.firstName];
cell.detailTextLabel.text = user.email;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *usersInSection = [dictionaryUsers objectForKey:[allKeys objectAtIndex:indexPath.section]];
User *usr = [usersInSection objectAtIndex:indexPath.row];
NSLog(@"user: %@, %@", usr.lastName, usr.firstName);
}
@end
Upvotes: 0
Views: 1377
Reputation: 171
First of all thumbs up for using a HelperClass for implementing general functions. Only when you do it, make it at least a singleton, so that you not always have to call:
helper = [[HelperClass alloc] init];
Or if you only have functions like createUser, these methods should be class methods.
Here are two general hints, which came to my mind, when looking at your code:
You have too many allocations in your code. For example in your TableViewController you do:
users = [[NSMutableArray alloc] init];
users = [helper createUser];
So first you allocate a new array and the first thing the createUser function does is to allocate another array in memory, which is then returned. Your first allocated memory space is never used.
When it comes to tableViews don't use dictionaries. Always stick with arrays. A dictionary is not ordered and when iterating through a dictionary you might get different results each time. An array is ordered and objectOfIndex:i will always return the same object.
So I adjusted your code to have a dynamic tableView sorting your users into sections by their city and sorting them alphabetically. (I guess this was what you wanted to achieve). The new code is not completely clean. You could try to use NSArray instead of NSMutableArray everywhere to save some memory for example.
Your User.h is untouched.
Here is the new HelperClass.h
// HelperClass.h
#import <Foundation/Foundation.h>
@interface HelperClass : NSObject
+ (HelperClass *)sharedHelperClass;
+ (NSMutableArray *) createUser;
+ (NSMutableArray *) getAllCitiesFromUserArray: (NSMutableArray *)userArray;
+ (NSMutableArray *)getUsersOfUsersArray: (NSMutableArray *)userArray fromCity: (NSString *)city;
@end
And the HelperClass.m
// HelperClass.m
#import "HelperClass.h"
#import "User.h"
@implementation HelperClass
+ (HelperClass *)sharedHelperClass
{
//This returns always the same object of HelperClass
static dispatch_once_t pred;
static HelperClass *_sharedHelperClass = nil;
dispatch_once(&pred, ^{ _sharedHelperClass = [[self alloc] init]; });
return _sharedHelperClass;
}
- (id)init{
self = [super init];
if (!self) {
return nil;
}
return self;
}
+ (NSMutableArray *) createUser
{
NSMutableArray *userArray = [[NSMutableArray alloc] init];
User *user1 = [[User alloc] init];
user1.firstName = @"Donald";
user1.lastName = @"Duck";
user1.email = @"[email protected]";
user1.city = @"Entenhausen";
User *user2 = [[User alloc] init];
user2.firstName = @"Micky";
user2.lastName = @"Maus";
user2.email = @"[email protected]";
user2.city = @"Entenhausen";
User *user3 = [[User alloc] init];
user3.firstName = @"Daisy";
user3.lastName = @"Duck";
user3.email = @"[email protected]";
user3.city = @"Frankfurt";
User *user4 = [[User alloc] init];
user4.firstName = @"Goofy";
user4.lastName = @"Goof";
user4.email = @"[email protected]";
user4.city = @"Berlin";
User *user5 = [[User alloc] init];
user5.firstName = @"Some";
user5.lastName = @"Body";
user5.email = @"[email protected]";
user5.city = @"Somewhere";
User *user6 = [[User alloc] init];
user6.firstName = @"Dagobert";
user6.lastName = @"Duck";
user6.email = @"[email protected]";
user6.city = @"Mainz";
[userArray addObject:user1];
[userArray addObject:user2];
[userArray addObject:user3];
[userArray addObject:user4];
[userArray addObject:user5];
[userArray addObject:user6];
return userArray;
}
+ (NSMutableArray *) getAllCitiesFromUserArray: (NSMutableArray *)userArray{
NSMutableArray *cityArray = [[NSMutableArray alloc] init];
for (User *user in userArray) {
if (![cityArray containsObject: user.city]){
[cityArray addObject:user.city];
}
}
//Sort the city array alphabetically (localizedCaseInsensitiveCompare even regards Umlaute)
[cityArray sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
return cityArray;
}
+ (NSMutableArray *)getUsersOfUsersArray: (NSMutableArray *)userArray fromCity: (NSString *)city{
NSMutableArray *usersOfCityArray = [[NSMutableArray alloc] init];
for (User *user in userArray) {
if ([user.city isEqualToString:city]){
[usersOfCityArray addObject:user];
}
}
//Sort the array of custom objects by key lastName
NSSortDescriptor *sortDescriptor =
[NSSortDescriptor sortDescriptorWithKey:@"lastName"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)];
usersOfCityArray = [[usersOfCityArray sortedArrayUsingDescriptors:@[sortDescriptor]]mutableCopy];
return usersOfCityArray;
}
@end
The new TableViewController.h
// TableViewController.h
#import <UIKit/UIKit.h>
@interface TableViewController : UITableViewController
@end
And the new TableViewController.m
// TableViewController.m
#import "TableViewController.h"
#import "HelperClass.h"
#import "User.h"
@interface TableViewController ()
@property (nonatomic,strong) NSMutableArray *users;
@property (nonatomic,strong) NSMutableArray *sectionHeaders;
@end
@implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//This gets the Array of Users from the HelperClass class method
//You could access the HelperClass Singleton with [HelperClass sharedHelperClass], but this is not needed in this case.
self.users = [HelperClass createUser];
self.sectionHeaders = [HelperClass getAllCitiesFromUserArray:self.users];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.sectionHeaders count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:section];
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
return sectionUsers.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [self.sectionHeaders objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:indexPath.section];
//Get users for the current city
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
//Get the user for the current cell
User *user = [sectionUsers objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:@"%@, %@", user.lastName, user.firstName];
cell.detailTextLabel.text = user.email;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get the current section city
NSString *city = [self.sectionHeaders objectAtIndex:indexPath.section];
//Get users for the current city
NSMutableArray *sectionUsers =[HelperClass getUsersOfUsersArray:self.users fromCity:city];
//Get the user for the current cell
User *user = [sectionUsers objectAtIndex:indexPath.row];
NSLog(@"user: %@, %@", user.lastName, user.firstName);
}
@end
Upvotes: 1