My problem is in getting the information from a controller(which happens to be my rootViewController) to another view. In trying to get access to it through the app delegate, I was not able to get it working. I have found how to do this, but this inturn created another problem of getting the view inside a modal view controller to actually display the data. Below I have posted both the appDelegate information, and an NSMutable Dictionary solution code for those that may need help too.
I had tried for more than a week to solve ths problem on my own. My issue ended up being how to access the appDelegate, which was why I was having a problem with the NSDictionary. So in the end the issue wasn't the NSDictionary, although had I gone further it would have been a problem I am sure.
Firstly I would like to thank TechZen for helping me to see I was over programming, and point me in the right direction.
Here is what I learned.
Assign your variable in the appDelegate.
AppDelegate.h
@interface AppDelegate : NSObject < UIApplicationDelegate, UINavigationControllerDelegate >
{
UIWindow *window;
UINavigationController *navController;
// Array to store the Makers Objects
NSMutableArray *makers;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navController;
@property (retain, nonatomic) NSMutableArray *makers;
@end
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
makers = [[NSMutableArray alloc] init] ;
}
In the ViewController.m assign the variable to the appDelegate. I did this inside a tableView function didSelectRowAtIndexPath.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// The line below loads it into the variable, the one above takes it and makes it available for other view Controllers.
Maker *maker = (Maker *)[appDelegate.makers objectAtIndex:indexPath.row];
// the combination of the above and below also loads the information into another array in this view controller, defined in an NSObject Controller called Maker (.h and .m files)
maker = [self.Makers objectAtIndex:indexPath.row];
Now in your view Controller you want to load the variable from the appDelegate, set it up like this.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Maker.h"
@class AppDelegate;
@interface DetailsViewController : UIViewController
{
AppDelegate *dappDelegate;
DetailsViewController *detailsView;
IBOutlet UITextView *makerDescription;
}
@property (retain, nonatomic) AppDelegate *dappDelegate;
@property (nonatomic, retain) DetailsViewController *detailsView;
@property (nonatomic, retain) IBOutlet UITextView *makerDescription;
@end
and in the viewController.m file;
#import "DetailsViewController.h"
#import "AppDelegate.h"
@synthesize dappDelegate;
- (void)viewWillAppear:(BOOL)animated // or ViewDidLoad not sure which is better.
dappDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSString *newLocalVariable = [dappDelegate.makers description];
NSLog(@"newLocalVariable: %@", [dappDelegate.makers description]);
// This is for verifying you have it loaded. 'description' is defined in the Maker NSObject, see below for those files, and above for where it was assigned originally
..... and assign it to what ever you want now!
I hope this helps everyone. You could at this point drop the NSArray from there into a NSDictionary, but the access is now with keys and values, so a bit more complicated at this point to access, but of course advantages. I just cannot get that totally down yet, and have backed away from that method to just use a NSArray for now.
Below is a sample of a Makers h and m file for you to see as well.
Maker.h
@interface Maker : NSObject
{
NSString *name;
NSString *address;
NSString *city;
NSString *postalcode;
NSString *country;
NSString *phonenumber;
NSString *email;
NSString *description;
NSString *services;
NSString *website;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSString *city;
@property (nonatomic, copy) NSString *postalcode;
@property (nonatomic, copy) NSString *country;
@property (nonatomic, copy) NSString *phonenumber;
@property (nonatomic, copy) NSString *email;
@property (nonatomic, copy) NSString *description;
@property (nonatomic, copy) NSString *services;
@property (nonatomic, copy) NSString *website;
- (id)initWithName:(NSString *)n address:(NSString *)a city:(NSString *)c postalcode:(NSString *)z country:(NSString *)o phonenumber:(NSString *)p email:(NSString *)e description:(NSString *)d services:(NSString *)s website:(NSString *)w;
@end
and its Maker.m file;
#import "ViolinMaker.h"
@implementation Maker
@synthesize name, address, city, postalcode, country, phonenumber, email, description, services, website;
- (id)initWithName:(NSString *)n address:(NSString *)a city:(NSString *)c postalcode:(NSString *)z country:(NSString *)o phonenumber:(NSString *)p email:(NSString *)e description:(NSString *)d services:(NSString *)s website:(NSString *)w;
{
self.name = n;
self.address = a;
self.city = c;
self.postalcode = z;
self.country = o;
self.phonenumber = p;
self.email = e;
self.description = d;
self.services = s;
self.website = w;
return self;
}
@end
I hope this helps others get this straight, as it really cost me a lot of time and I hope you can get a bit from what I learned.
Sincerely, Kirk
I don't see any point where you populate the selectedMaker
ivar in the DetailsViewController
with data from the app delegate's `selectedMaker'. Just because they have the same name doesn't mean they share the same data.
You need to assign or copy the values from the app delegate to the view controller. The quick and dirty way is to do something like:
@implementation DetailsViewController
...
-(void) viewDidLoad{
//selectedMaker=[[UIApplication sharedApplication] selectedMaker]; <-- this is wrong
//Edit, this is the correct call to app delegate
selectedMaker=[[[UIApplication sharedApplication] delegate] selectedMaker];
}
Edit01:
So... at the suggestion of TechZen i have tried to move my NSDictionary out of my RootViewController.
(1) I'm not sure why you have the SelectedMaker
class of what it is supposed to accomplish. You seem to have confused the class with a NSMutableDictionary
. The class doesn't have any apparent reason to return a dictionary containing the values of it's own iVars. This is completely redundant. You already appear to have a class called ViolinMaker
that encapsulates all the data for each violin maker record.
(2) The initializations methods for SelectedMaker
are not implemented correctly. It looks like you have to call -[SelectedMaker initWithsName:..]
before you call -[SelectedMaker init]
otherwise init has no clue what the keys are.
(3) In any case, in the didSelectRow
method, you don't actually initialize an instance of SelectedMaker
. This line:
SelectedMaker *selectedMaker = [[[NSMutableDictionary alloc]retain] initWithObjects: objects forKeys: keys];
Does not create an instance of SelectedMaker
but rather a NSMutableDictionary
and more or less cast it to the SelectedMaker
class. This is why you get the compiler warning from the for-loop.
(4) I don't see any need for the SelectedMaker
class at all. These lines:
ViolinMakerAppDelegate *appDelegate = (ViolinMakerAppDelegate *)[[UIApplication sharedApplication] delegate];
ViolinMaker *violinMaker = (ViolinMaker *)[appDelegate.violinMakers objectAtIndex:indexPath.row];
violinMaker = [self.filteredViolinMakers objectAtIndex:indexPath.row];
Appear to provide you all the information you need to populate any particular row in your table or your detail view. You can use these three line in any view in which you need to access the data in appDelegate.violinMakers'. The
violinMaker`object contains all the data you need.
I think you are making this more complicated than it has to be. All you need is (A) a class that encapsulates the data for each record fetched from your SQL. In this case it looks like ViolinMaker does this. (B) You need an array (or other collection) in the app delegate to store the multiple ViolinMaker instances. (C) You need code in each viewcontroller that will access the array/collection in the app delegate so that the viewcontroller can select the ViolinMaker instances it needs.
Edit02:
no I cannot use those 3 lines, as the 'objectAtIndex:indexPath.row' is only available inside the didSelectRow function. Which means I would have to reconstruct the table and all of its data.
You just define the dictionary once as an instance variable in your app delegate. So, you would have a mutable dictionary where each value was ViolinMaker
and each key was some attribute of a violin maker such as the name. Let's call that violinMakersDict
.Then, anywhere in your app, you would access the dictionary by first calling the app delegate and the accessing the violinMakersDict.
To populate a table, you would need to extract the some values as an array. Most likely, you would takes the keys which are names of violin makers. Then you would sort the array alphabetically, then you would populate each row with the value in the array at the index.row value.
Likewise, if you need to add data in one view, you can write to the violinMakersDict
and then access that data from another view by again calling the app delegate.