iPhone - UINavigationController question - iphone

I want to display some data on table, let's call it "TabeView" app.
So I created a "navigation-based" application on XCode and it gives me 4 files in the "classes folder".
RootViewController.h
RootViewController.m
TableViewAppDelegate.h
TableViewAppDelegate.m
Now, I wanted to set up the data in TableViewAppDelegate using the "didFinishLaunchingWithOptions" method, which I did using an array.
Then, I need to "send" this array to the RootViewController. I have an array variable in RootViewController so I assume that I need to "set" the array variable in RootViewController from the TableViewAppDelegate. How can I do this?
The problem I am having is, that I don't know how to set the array variable in RootViewController from TableViewAppDelegate. I want to know if something like below is possible
....
[RootViewController setMyArray:myArray];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
....
But I have no idea how to call "RootViewController".
Hopefully I made some sense. Thank you.

First, create a property in your RootViewController class for the array variable. So e.g. if your array variable is called myArray your code might look something like this:
In RootViewController.h:
#import <UIKit/UIKit.h>
#interface RootViewController : UITableViewController {
NSArray *myArray;
}
#property (nonatomic, retain) NSArray *myArray;
#end
and add the corresponding #synthesize line in RootViewController.m:
#import "RootViewController.h"
#implementation RootViewController
#synthesize myArray;
// methods here
#end
Now you can set the myArray member of a RootViewController object like this:
myRootViewController.myArray = [NSArray arrayWithObjects:#"foo", #"bar", nil];
Now, in your app delegate class, you can use the viewControllers property of self.navigationController to return the view controllers in the navigation stack. The root controller will always be at index 0. viewControllers will return an NSArray, whose elements are of type NSObject, so you need to cast to a RootViewController pointer too. Here it is in two lines, to make the cast explicit:
// get a pointer to the root view controller
id obj = [self.navigationController.viewControllers objectAtIndex:0];
// cast it to a RootViewController pointer
RootViewController* rvc = (RootViewController*)obj;
// Now you can set the array
rvc.myArray = someArray;
(In order to use the RootViewController class name in your app delegate class you'll need to import the relevant header file - put this at the top of TableViewAppDelegate.m:
#import "RootViewController.h"
And that's it!
p.s. Bear in mind that declaring your myArray property as type (nonatomic, retain) means that your RootViewController object will end up pointing to the same instance of NSArray that you pass to it. So, for example:
NSMutableArray *array = [NSMutableArray arrayWithObjects: #"foo", #"bar", nil];
myRootViewController.myArray = array;
[array removeAllObjects]; // myRootViewController.myArray is now empty!
You can use (nonatomic, copy) instead, in which case your RootViewController object will make a copy of the array you pass in and retain that instead. Changes to the array once you've assigned it to your RootViewController object won't affect the copy.

navigationController.myArray = myArray;
before
[window addSubview:navigationController.view];

Related

How Can I Access my ViewController's Property Variables From Another Class?

Ok, this is really bugging me and I am sure the solution is simple... I am unable to set my ViewController's property variables from another class (SeverConnect.m), which I have declared and synthesized properly in my ViewController's .h/.m files:
ServerConnect.h:
#import <Foundation/Foundation.h>
#import "ViewController.h"
#import "Contact.h"
#class ViewController;
#interface ServerConnect : NSObject
{
Contact *newContact;
NSString *codeRawContent;
NSMutableArray *contactListCopy;
... //Other variables declared here, but not shown in order to save space
Inside ServerConnect.m:
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"parserDidFinish");
newContact = [[Contact alloc] initWithCodeInfo:(NSString *)codeInfo
contactName:(NSString *)completeName
contactImage:(UIImage *)profileImage
contactWebSite:(NSString *)codeRawContent];
[contactListCopy insertObject:newContact atIndex:0];
[ViewController setContactList:contactListCopy]; //Automatic Reference Counting Error Occurs Here: "No known class method for selector 'setContactList:'"
}
As I mentioned above, I have declared and synthesized the property variable, "contactList", in my ViewController's .h/.m files (with no errors):
#property (nonatomic, retain) NSMutableArray *contactList; //In ViewController's .h file
#synthesize contactList; //In ViewController's .m file
Can someone tell me what I am doing wrong? Thanks in advance for any help you can provide!
you are trying to access an instance property on a class:
[ViewController setContactList:contactListCopy];
you need to first create an instance of the ViewController class, and then set its property. Something like this:
ViewController *viewController = [[ViewController alloc] init];
[viewController setContactList:contactListCopy];
In this line of code:
[ViewController setContactList:contactListCopy];
you should be using a variable of type ViewController. The way you are using it, it should be a class method, not a property.
Write something like:
ViewController *viewController = [[ViewController alloc] init];
[viewController setContactList:contactListCopy];

pass data from mainView to a subview

I am building a utility-based application, the data is stored in the MainViewController, and now I know how to pass data to the FlipsideViewController (many regards to this thread BTW, Sending data from Mainview to Flipside?). But I am getting the data onto an subview (subclass of UIView) that I have added to the flipside view. How can I pass data to this subview? I saw there is already a delegate and protocol set up in the FlipsideViewController.h, I am really new to the delegate sort of things. Any help would be greatly appreciated!
Updates:
On the main view, I have a couple of text fields for users to input to create an object. All the objects are stored in an array. Namely, my data is created and stored in the MainViewController. Now on the flip side, I have a custom UIView subclass which allows me to do my own drawing based on the data in that array. What I need to do here is pass the data that stored in MainViewController to this subview. Here is my relevant code:
In the MainViewController.m
- (IBAction)showInfo:(id)sender {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.delegate = self;
controller.receiver = data;//this is what I've done.
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
In the FlipsideViewController.h
#protocol FlipsideViewControllerDelegate;
#interface FlipsideViewController : UIViewController {
id <FlipsideViewControllerDelegate> delegate;
DataModel *receiver; //create a property to receive the data transferred from main view
}
#property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;
#property (nonatomic, retain) DataModel *receiver;
- (IBAction)done:(id)sender;
#end
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
In the above code, "data" is an DataModel object declared in the MainViewController.h file.
And I want to do my custom drawing in drawing class (subclass of UIView), how can I pass data from the FlipsideViewControllerto this subview? Do I need to make use of delegate declared in the FlipsideViewController.h file? Thanks in advance!
I have had a quick look at the template and think you are getting confused with what the delegate is being used for.
The delegate in this template is not transferring data. When you have clicked the done button it calls back to MainViewController and asks it to call the dismissModalViewControllerAnimated method so that it can remove the view controller. This seems a bit superflous as the documentation states
If you call this method on the modal view controller itself, however, the modal view controller automatically forwards the message to its parent view controller.
Therefore you don't really need to call the parent to do this.
In Interface builder you can see that the FlipsideView.xib has it's File's Owner set to FlipsideViewController.xib.
Now if you right click the File's Owner you will see that view is connected to View this basically means that view is the name of the property in FlipsideViewController and View is the element in Interface Builder.
Therefore we can access elements in the xib file from FlipsideViewController using outlets.
To say draw a label you will need to do a couple of things
First add a property in the .h and synthesize it in the .m like
// FlipsideViewController.h
#interface FlipsideViewController : UIViewController
#property (nonatomic, retain) IBOutlet UILabel *testLabel; // <----- Added this
#property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
#end
// FlipsideViewController.m
#implementation FlipsideViewController
#synthesize delegate = _delegate;
#synthesize testLabel = _testLabel; // <----- Added this
// More methods
- (void)dealloc
{
[_testLabel release]; // Always do you memory management
[super dealloc];
}
Then back in Interface Builder
Add a UILabel element to your view
ctrl + drag from File's Owner to the UILabel you added
Select the label in my example it is testLabel
Now these are hooked up correctly. The place where you want to be setting the value of the label is in viewDidLoad: which you can now do like this
- (void)viewDidLoad
{
[super viewDidLoad];
self.testLabel.text = #"It Works"; // You would use the data passed in from `MainViewController`
}
I find the easiest way to pass data from one view to another is by directly setting the data in the next view from the original view.
For example;
In your FlipsideViewController.h, declare a 'container' for the data you want to pass. It must be the same class on both sides to work properly, ie. NSArray to NSArray, NSMutableDictionary to NSMutableDictionary.
NSMutableArray *newData;
...
#property (nonatomic, retain) NSMutableArray *newData; // This allows you to access this object from outside this class.
and in FlipsideViewController.m
#synthesize newData;
...
[newData release];
Now we need to pass the data, so to speak. Let's say the data we want to 'send' is stored in a NSMutableArray called 'results'.
In our MainViewController.m, when we are instantiating our next view controller (in this case FlipsideViewController) we can directly reference the newData mutable array after we initalize the nib.
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideView" bundle:nil];
controller.newData = results;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
Make sure you are importing your FlipsideViewController in your MainViewController.h file.
If the property is declared in your .h file, you can pretty much reference the contents of the object from anywhere within the view stack!
Hope that helps :D

Passing contents of array from one class to another

I've got an array populating a small tableView in a DetailView class, and when the user presses a button I need the array to be sent to another View Controller, to populate a tableView there, but I'm having some difficulty getting it working. This is what I've been trying to do so far:
*DetailViewController.m*
#import "DetailViewController.h"
#import "OtherViewController.h"
-(IBAction) toCart:(id)sender {
OtherViewController *oVC = [[OtherViewController alloc] init];
oVC.shoppingList = sList;
NSLog(#"Ingredients count %d", [sList count]); //This returns a number, so the sList definitely contains values, and the method is definitely being called.
[oVC release];
}
*OtherViewController.m*
#import "OtherViewController.h"
#import "DetailViewController.h"
#synthesize shoppingList;
-(void) viewWillAppear: (BOOL)animated {
NSLog(#"list count: %d", [shoppingList count]); // This returns 0
}
sList is populated elsewhere in the class, and sList and shoppingList are both declared in their respective .h files, with #property (nonatomic, retain)...
Any help much appreciated!
As you are having taBbarcontroller, so you can proceed as follows :
Create references of your you viewControllers(which are associated with tabbar as topViewController) in your appDelegate.
otherViewController = [[tabBarController.viewControllers objectAtIndex:<tabIndex>] topViewController];
make it as #property in appDelegate so that you can access it anywhere in your app.
now,
-(IBAction) toCart:(id)sender {
//appDelegate <--- get reference to your application delegate using [[UIApplication sharedApplicaiton]delegate] do not forget to properly type cast it.
OtherViewController *oVC = [appDelegate otherViewController];
oVC.shoppingList = sList;
NSLog(#"Ingredients count %d", [sList count]);
//This returns a number, so the sList definitely contains values, and the method is definitely being called.
// [oVC release]; no need to release it...
}
//also make sure you do not initialize shoppingList of otherViewController in viewDidLoad(or any other method) of otherViewController, else it will be overwritten(lost its previous reference).
in your appDelegate's .h write
#property OtherViewController *otherViewController;
in appDelegate's.m
#synthesize otherViewController;
in appDelegates's .m (method didFinishLaunchingWithOptions: ) write
otherViewController = [[tabBarController.viewControllers objectAtIndex:<tabIndex>] topViewController];
Thanks
In toCart:, you are creating an OtherViewController and then immediately throwing it away. Whatever OtherViewController is calling -viewWillAppear, it isn't the one you're creating in toCart:. How is that object created and put on the screen? You need a pointer to it to modify it.
Better, though, would be to move your model data out of the view controllers and put it in a single ShoppingCart object. Then all your view controllers would have a reference to it (or you can make ShoppingCart a singleton if that makes sense in your program). This way, any time you change the shopping cart from anywhere, all views will correctly update without having to tell every view controller about every other view controller.

Accessing NSMutableArray in an object from different object

How can I get access to a NSMutableArray that has been hydrated in different Class?
There is my sample code:
Class1.h : I have an iVar NSMutableArray *anArray;
And I #synthesize anArray; it in Class1.m
In the RootViewController I import the Class1.h and addd #Class "Class1";
The in the interface I add the Class1 *aClass1; in the RootViewController.m I #synthesize it and in the ViewWillAppear
aClass1 = [[Class1 alloc] init];
aClass1.anArray = [[NSMutableArray alloc] initWithObjects: #"string1",#"string2",nil];
NSLog(#"aClass1.anArray is Class1 %#",aClass1.anArray); // It works as I expected
Now in the new class I call it DetailsViewController
Same as the RootViewController.h I imported the .h and #class "Class1";.
Also in the DetailsViewController.m I have imported the "Class1.h"
So now in the DetailsViewController I try to do this in the viewWillAppear
NSLog(#"aClass1.anArray in DetailsViewController %#",aClass1.anArray); // PROBLEM: It comes back as null
I have added this sample project in this address: http://www.epicdesign.com.au/test2.zip
You just forgot to set the aClass1 ivar of the details view controller before you pushed it onto the navigation controller. Here is the code that should be in your didSelectRowAtIndexPath method:
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// ...
// Pass the selected object to the new view controller.
detailViewController.aClass1 = aClass1; // this line was added
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Once you add the line that I added above, your array will now show up correctly in the detail view controller.
You're accessing a property that you haven't declared yet in the Class1.h, so you must add there:
#property (nonatomic, copy) NSMutableArray *anArray;
Since it should work, I prefer not to pass any NSMutableArray as parameter. You should better declare a NSArray property in Class1.h to pass it to your methods and then mutableCopy it where you want to make modifications to the array (only inside the methods). And remember that mutableCopy and copy increase the retain count of your array, so you must release it when you are done.

Pass variable to another view

I'm trying to set a variable in another view.
I'm in a view which I have named ProgramViewController and from here I would like to set a variable named bands in MyViewController.
I thought it would be as simple as
MyViewController *myViewController = [[MyViewController alloc] init];
myViewController.bands = #"hello world";
[myViewController release];
And in the header of MyViewController:
#interface MyViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSString *bands;
}
#property (nonatomic, retain) NSString *bands;
That does not work, though.
Can anyone please tell me what I am doing wrong?
EDIT:
I synthesize bands in MyViewController:
#synthesize pageNumberLabel, tableProgram, bands;
But when trying to print it with NSLog in the viewDidLoad of MyViewController I get (null)
NSLog(#"%#", bands);
You need to synthesize the bands variable in MyViewController.m
#synthesize bands;
A variable needs to be synthesize in order to use it as a public property outsize of a class in Objective-C
I solved this in another way. I managed to load the data in MyViewController instead. I was dealing with a page controller and had to populate a UITableView but had troubles loading the data.
This is solved in a completely other way now.