Is there a way to shorten my CountryViewController.m without hard coding? - iphone

I would like to know if there's a way to shorten my CountryViewController.m because I will be adding another else if statement every time I add a new country.
I am using a UITableViews that pushes a new table view.
RootViewController.m
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
    
    ASIA = [[NSMutableArray alloc] init];
    EU = [[NSMutableArray alloc] init];
    [ASIA addObject: #"China"];
    [ASIA addObject: #"Japan"];
    [ASIA addObject: #"Korea"];
    [EU addObject: #"France"];
    [EU addObject: #"Italy"];
    [EU addObject: #"Switzerland"];
    self.title = #"Continent";
}
CountryViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
if ([self.title isEqualToString: #"China"]) {
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Beijing"];
[_listOfCities addObject: #"Hong Kong"];
}
else if ([self.title isEqualToString: #"Japan"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Tokyo"];
}
else if ([self.title isEqualToString: #"Korea"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Seoul"];
}
else if ([self.title isEqualToString: #"France"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Paris"];
[_listOfCities addObject: #"Versailles"];
}
else if ([self.title isEqualToString: #"Italy"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Rome"];
}
else if ([self.title isEqualToString: #"Switzerland"]){
_listOfCities = [[NSMutableArray alloc] init];
[_listOfCities addObject: #"Bern"];
}
[self.tableView reloadData];
}

A simple way is to use a property list and include that as a bundle resource (i.e. just add it to your project).
For example, if your property list looks like this:
You can then load it with
countries = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"CountryData" ofType:#"plist"]];
and use it as a normal dictionary or array, i.e.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
NSString* countryName = self.title;
NSDictionary* country = [countries objectForKey:countryName];
NSArray* cities = [country objectForKey:#"Cities"];
NSString* continent = [country objectForKey:#"Continent"];
_listOfCities = cities;
[self.tableView reloadData];
}
Plist files can be edited easily in XCode.

Related

Load more pages in TTLauncherView

In my implementation of TTLauncherView, only loads the first page. Why?
I have 47 items in array, 47 items div 9 items by page, I should have 6 pages.
Thanks for helping.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSMutableString *jsonString = [[NSMutableString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
NSArray *photos = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
launcherView = [[TTLauncherView alloc] initWithFrame:self.view.bounds];
launcherView.backgroundColor = [UIColor whiteColor];
launcherView.delegate = self;
launcherView.columnCount = 3;
launcherView.persistenceMode = TTLauncherPersistenceModeNone;
NSMutableArray *itemArray = [[NSMutableArray alloc] init];
for (NSDictionary *photo in photos)
{
NSString *iconURLString = [NSString stringWithFormat:#"http://farm%#.static.flickr.com/%#/%#_%#_s.jpg",
[photo objectForKey:#"farm"], [photo objectForKey:#"server"], [photo objectForKey:#"primary"], [photo objectForKey:#"secret"]];
NSDictionary *title = [photo objectForKey:#"title"];
NSString *itemTitle = [title objectForKey:#"_content"];
TTLauncherItem *itemMenu = [[[TTLauncherItem alloc] initWithTitle:itemTitle
image:iconURLString
URL:nil
canDelete:NO] autorelease];
[itemArray addObject:itemMenu];
}
launcherView.pages = [NSArray arrayWithObject: itemArray];
[self.view addSubview:launcherView];
}
As I recall, TTLauncherView doesn't break up the TTLauncherItem's into pages automatically. You need an array of arrays. All of the launcher item's in the first array will be on the first page, all the launcher item's in the second array will be on the second page etc. It has been a long time since I've used it, but I think that's how it worked.
My modified code with the hint of #Darren
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSMutableString *jsonString = [[NSMutableString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
NSArray *photos = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
NSMutableArray *itemArray = [[NSMutableArray alloc] init];
NSMutableArray *pageArray = [[NSMutableArray alloc] init];
NSNumber *countPage = [[NSNumber alloc] initWithInt:0];
for (NSDictionary *photo in photos)
{
NSString *iconURLString = [NSString stringWithFormat:#"http://farm%#.static.flickr.com/%#/%#_%#_s.jpg",
[photo objectForKey:#"farm"], [photo objectForKey:#"server"], [photo objectForKey:#"primary"], [photo objectForKey:#"secret"]];
NSString *photoCount = [photo objectForKey:#"photos"];
NSDictionary *title = [photo objectForKey:#"title"];
NSString *itemTitle = [title objectForKey:#"_content"];
TTLauncherItem *itemMenu = [[[TTLauncherItem alloc] initWithTitle:itemTitle
image:iconURLString
URL:nil
canDelete:NO] autorelease];
itemMenu.badgeValue = photoCount;
[itemArray addObject:itemMenu];
int value = [countPage intValue];
countPage = [NSNumber numberWithInt:value + 1];
if (countPage == [NSNumber numberWithInt:9]){
countPage = [NSNumber numberWithInt:0];
[pageArray addObject:itemArray];
itemArray = [[NSMutableArray alloc] init];
}
}
[pageArray addObject:itemArray];
launcherView = [[TTLauncherView alloc] initWithFrame:self.view.bounds];
launcherView.backgroundColor = [UIColor blackColor];
launcherView.delegate = self;
launcherView.columnCount = 3;
launcherView.persistenceMode = TTLauncherPersistenceModeNone;
launcherView.pages = pageArray;
[self.view addSubview:launcherView];
}

Memory management advice - how to handle Zombies?

In the below sample code, I am a bit lost as to why I am getting a NZombie on the line:
[Category getInitialDataToDisplay:[self getDBPath]];
I have looked through SO posts and other documentation but am new to objective-c and am spinning my wheels on this.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//Copy database to the user's phone if needed.
[self copyDatabaseIfNeeded];
// Init the Array
activeCategories = [[NSMutableArray alloc] init];
activeSubjects = [[NSMutableArray alloc] init];
categories = [[NSMutableArray alloc] init];
subjects = [[NSMutableArray alloc] init];
quotes = [[NSMutableArray alloc] init];
quoteMaps = [[NSMutableArray alloc] init];
//Initialize the Category array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.categories = tempArray;
[tempArray release];
//Once the db is copied, get the initial data to display on the screen.
[Category getInitialDataToDisplay:[self getDBPath]];
//populate active subjects and categories:
activeCategories = [self getActiveCategories];
activeSubjects = [self getActiveSubjects];
// sort data
NSSortDescriptor *categorySorter;
NSSortDescriptor *subjectSorter;
categorySorter = [[NSSortDescriptor alloc]initWithKey:#"category_title" ascending:YES];
subjectSorter = [[NSSortDescriptor alloc]initWithKey:#"title" ascending:YES];
NSArray *sortDescriptorsCat = [NSArray arrayWithObject:categorySorter];
NSArray *sortDescriptorsSub = [NSArray arrayWithObject:subjectSorter];
[self.categories sortUsingDescriptors:sortDescriptorsCat];
[self.subjects sortUsingDescriptors:sortDescriptorsSub];
[categorySorter release];
[subjectSorter release];
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
...
- (void)dealloc {
[activeSubjects release];
[activeCategories release];
[categories autorelease];
[subjects autorelease];
[quotes autorelease];
[quoteMaps autorelease];
[navigationController release];
[window release];
[super dealloc];
}
Here is the getInitialDataToDisplay:
+ (void) getInitialDataToDisplay:(NSString *)dbPath {
// Use this section to bring in database and populate the array
FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
[database open];
QuotesAppDelegate *appDelegate = (QuotesAppDelegate *)[[UIApplication sharedApplication] delegate];
//appDelegate.categories = [appDelegate.categories sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
//POPULATE THE SUBJECT
FMResultSet *result_subjects = [database executeQuery:#"select * from SUBJECT"];
while([result_subjects next]) {
NSInteger primaryKey = [result_subjects intForColumn:#"SUBJECT_ID"];
Subject *sub = [[Subject alloc] initWithPrimaryKey:primaryKey];
sub.title = [result_subjects stringForColumn:#"SUBJECT"];
sub.category_title = [result_subjects stringForColumn:#"CATEGORY"];
sub.active = [result_subjects intForColumn:#"ACTIVE"];
sub.isDirty = NO;
[appDelegate.subjects addObject:sub];
[sub release];
}
FMResultSet *result_categories = [database executeQuery:#"select distinct category from SUBJECT"];
while([result_categories next]) {
Category *cat = [[Category alloc] init];
cat.category_title = [result_categories stringForColumn:#"CATEGORY"];
NSLog(#"loading category: %#", cat.category_title);
QuotesAppDelegate *appDelegate = (QuotesAppDelegate *)[[UIApplication sharedApplication] delegate];
for (Subject *sb in appDelegate.subjects){
if([cat.category_title isEqualToString:sb.category_title]){
[cat.subjects addObject:sb];
NSLog(#" Adding subject: %# cat.subjects.count=%i", sb.title, cat.subjects.count);
}
}
[appDelegate.categories addObject:cat];
[cat release];
}
//POPULATE THE QUOTES
FMResultSet *result_quotes = [database executeQuery:#"select * from QUOTE"];
while([result_quotes next]) {
Quote *sub = [Quote alloc];
sub.quote_id = [result_quotes stringForColumn:#"QUOTE_ID"];
sub.quote_date = [result_quotes stringForColumn:#"DATE"];
sub.title = [result_quotes stringForColumn:#"DESC1"];
sub.desc2 = [result_quotes stringForColumn:#"DESC2"];
sub.excerpt = [result_quotes stringForColumn:#"EXCERPT"];
sub.note = [result_quotes stringForColumn:#"NOTES"];
sub.isDirty = NO;
[appDelegate.quotes addObject:sub];
[sub release];
}
//POPULATE THE QUOTE_MAPS
FMResultSet *result_quote_map = [database executeQuery:#"select * from QUOTE_MAP"];
while([result_quote_map next]) {
QuoteMap *sub = [QuoteMap alloc];
sub.quote_id = [result_quote_map stringForColumn:#"QUOTE_ID"];
sub.quote_map_id = [result_quote_map stringForColumn:#"QUOTE_MAP_ID"];
sub.subject_id = [result_quote_map stringForColumn:#"SUBJECT_ID"];
sub.isDirty = NO;
[appDelegate.quoteMaps addObject:sub];
[sub release];
}
[database close];
NSLog(#"Count of categories: %i", appDelegate.categories.count);
NSLog(#"Count of subjects: %i", appDelegate.subjects.count);
NSLog(#"Count of quotes: %i", appDelegate.quotes.count);
NSLog(#"Count of quoteMaps: %i", appDelegate.quoteMaps.count);
}
Here is the getDbPath:
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:#"reference.db"];
}
Sometimes, the best thing to do is build->analyze ( cmd shift b ). This will point out your bug right away in almost all cases.
Best of luck!
categories = [[NSMutableArray alloc] init];
.
.
//Initialize the Category array.
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
self.categories = tempArray;
[tempArray release];
u've setup categories, then setup the tempArray, replaced the one in categories with it thus making a leak, then released the temp arrayObject, which what categories is now also pointing on, so unless "self.categories" is a retained property it will be a zombie. there seems to be something wrong there.
I may need to see some more of your code (the property declarations and their synthesis to make sure.
is the Zombie called on "getInitialDataToDisplay" or on "getDBPath"
try dividing it on 2 lines to know pin point more
I think you have not declare Category as retained property in .h file.If not, add following line in your .h file
#property (nonatomic, retain) NSArray Category;
And synthesize the property in .m as-
#synthesize Category;
I think it will help ....

How to add a search bar to a table view that is populated from a plist

I have tried using a couple of different search bar examples but I have not had any luck with adding a search bar. I would really appreciate any help that can be provided. The following is the code and I was using the search bar controller example.
if(CurrentLevel == 0) {
//Initialize our table data source
NSArray *tempDict = [[NSArray alloc] init];
self.tableDataSource = tempDict;
[tempDict release];
Midwest_DigestiveAppDelegate *AppDelegate = (Midwest_DigestiveAppDelegate *)[[UIApplication sharedApplication] delegate];
self.tableDataSource = [AppDelegate.data valueForKey:#"Rows"];
//Initialize the array.
NSMutableArray *listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObjectsFromArray:tableDataSource];
//Initialize the copy array.
NSMutableArray *copyListOfItems = [[NSMutableArray alloc] init];
//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
}
else
self.navigationItem.title = CurrentTitle;
//Initialize the array.
NSMutableArray *listOfItems = [[NSMutableArray alloc] initW];
[listOfItems addObjectsFromArray:tableDataSource];
//Initialize the copy array.
NSMutableArray *copyListOfItems = [[NSMutableArray alloc] init];
//Add the search bar
self.tableView.tableHeaderView = searchBar;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
}
- (void) searchTableView {
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in listOfItems)
{
NSArray *array = [dictionary objectForKey:#"Title"];
[searchArray addObjectsFromArray:array];
}
for (NSString *sTemp in searchArray)
{
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}

Autoreleased NSMutableArray not populated

I want to populate an array like this:
NSMutableArray *array = [self methodThatReturnsAnArray];
In the "methodThatReturnsAnArray"-method I create an array like this:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
When I'm finished populating "arrayInMethod" I'm returning the array and in order to prevent a memory leak I'm using:
return [arrayInMethod autorelease];
However the "array"-variable is never populated. When removing the "autorelease" it works fine though. What should I do in order to make sure that the returned object i released?
EDIT
+ (NSMutableArray *)buildInstants:(NSArray *)huntsArray {
NSMutableArray *goGetObjects = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [huntsArray count]; i++) {
NSDictionary *huntDict = [huntsArray objectAtIndex:i];
PHGoGet *goGet = [[PHGoGet alloc] init];
goGet.title = [huntDict objectForKey:#"title"];
goGet.description = [huntDict objectForKey:#"description"];
goGet.start = [huntDict objectForKey:#"start"];
goGet.end = [huntDict objectForKey:#"end"];
goGet.ident = [huntDict objectForKey:#"id"];
if ((CFNullRef)[huntDict objectForKey:#"image_url"] != kCFNull) {
goGet.imageURL = [huntDict objectForKey:#"image_url"];
} else {
goGet.imageURL = nil;
}
if ((CFNullRef)[huntDict objectForKey:#"icon_url"] != kCFNull) {
goGet.iconURL = [huntDict objectForKey:#"icon_url"];
} else {
goGet.iconURL = nil;
}
goGet.longitude = [huntDict objectForKey:#"lng"];
goGet.latitude = [huntDict objectForKey:#"lat"];
goGet.companyIdent = [huntDict objectForKey:#"company_id"];
[goGetObjects insertObject:goGet atIndex:i];
[goGet release];
}
return [[goGetObjects copy] autorelease];
}
Try using the convienence method for NSMutableArray... change:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
To...
NSMutableArray *arrayInMethod = [NSMutableArray array];
array will return an autoreleased object.
First of all, I recommend you not to return a NSMutableArray from any method. It's better to use NSArray for that to avoid some very difficult to debug problems. My proposition is:
You declare the mutable array and populate it:
NSMutableArray *arrayInMethod = [[[NSMutableArray alloc] init] autorelease];
Then you return an autoreleased copy:
return [[arrayInMethod copy] autorelease];
And finally, when you take the returned array, you make it mutable again (only if you need to change it):
NSMutableArray *array = [[self methodThatReturnsAnArray] mutableCopy];
When you're done with the array, you release it:
[array release];

UISearchBar - search a NSDictionary of Arrays of Objects

I'm trying to insert a search bar in a tableview, that is loaded with information from a NSDictionary of Arrays. Each Array holds and object. Each object has several properties, such as Name or Address.
I've implemented the methods of NSSearchBar, but the code corresponding to the search it self, that i have working on another project where the Arrays have strings only, is not working, and I can't get to thr problem.
Here's the code:
'indiceLateral' is a Array with the alphabet;
'partners' is a NSDictionary;
'RLPartnersClass' is my class of Partners, each one with the properties (name, address, ...).
-(void)handleSearchForTerm:(NSString *)searchTerm {
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
[self resetSearch];
for (NSString *key in self.indiceLateral) {
NSMutableArray *array = [partners valueForKey:key];
NSMutableArray *toRemove = [[NSMutableArray alloc] init];
for (NSString *name in array) {
if ([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location == NSNotFound)
[toRemove addObject:name];
}
if ([array count] == [toRemove count])
[sectionsToRemove addObject:key];
[array removeObjectsInArray:toRemove];
[toRemove release];
}
[self.indiceLateral removeObjectsInArray:sectionsToRemove];
[sectionsToRemove release];
[theTable reloadData];
}
Can anyone help me please?
Thanks,
Rui Lopes
I've done it.
Example:
-(void)handleSearchForTerm:(NSString *)searchTerm {
NSMutableDictionary *finalDict = [NSMutableDictionary new];
NSString *currentLetter = [[NSString alloc] init];
for (int i=0; i<[indiceLateral count]; i++) {
NSMutableArray *elementsToDict = [[[NSMutableArray alloc] init] autorelease];
currentLetter = [indiceLateral objectAtIndex:i];
NSArray *partnersForKey = [[NSArray alloc] initWithArray:[partnersCopy objectForKey:[indiceLateral objectAtIndex:i]]];
for (int j=0; j<[partnersForKey count]; j++) {
RLNames *partnerInKey = [partnersForKey objectAtIndex:j];
NSRange titleResultsRange = [partnerInKey.clientName rangeOfString:searchTerm options:NSDiacriticInsensitiveSearch | NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0){
NSLog(#"found: %#", partnerInKey.clienteCity
[elementsToDict addObject:partnerInKey];
}
}
[finalDict setValue:elementsToDict forKey:currentLetter];
}
NSMutableDictionary *finalResultDict = [finalDict mutableDeepCopy];
self.partners = finalResultDict;
[finalResultDict release];
[theTable reloadData];
}