PDA

View Full Version : Passing Objects Between Views




Lakario
Oct 29, 2008, 05:47 PM
I am having some difficulty trying to figure out how to pass an item between the Views in my applications. My program is a NavigationController based app that starts out with a table containing information about each item. When the user clicks on an item I want to take them to an ItemViewController nib that takes an Item object and populates the fields on the page based on the properties of the Item. The trouble is, no matter how many different ways I try to set the Item property of ItemViewController, it always end up null when the view loads. The item object is obtained programatically in the table view's click event on each row and then I initialize the ItemViewController and call its setItem method to specify the object. I attempted to implement my own setter method and when I stepped into it a call to self.item returned the correct object, but as soon I try to retrieve the item with my getter it is null.

Where did my object go?

Additionally, could someone show me how to manually implement my properties so that they are not generated for me? I'd like to slap some breakpoints in the setters to see if I can get a better feel for what's going on.

RootViewController.m (excerpt)

(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

// Navigation logic -- create and push a new view controller
iPhoneHelloWorldAppDelegate *appDelegate = (iPhoneHelloWorldAppDelegate *)[[UIApplication sharedApplication] delegate];
Item *item = (Item *)[appDelegate.items objectAtIndex:indexPath.row];

if(self.itemView == nil) {
ItemViewController *viewController = [[ItemViewController alloc] initWithNibName:@"ItemViewController" bundle:[NSBundle mainBundle]];
self.itemView = viewController;
[viewController release];
}

[self.itemView setItem: item]; // self.itemView.item is always nil. even when item is not
[self.navigationController pushViewController:self.itemView animated:YES];
self.itemView.title = [item itemName];
//[item release];
//[self.itemView.itemDescription setText:[item itemDescription]]; // This call works fine.
]


ItemViewController.h

@interface ItemViewController : UIViewController {
IBOutlet UITextView *itemDescription;
Item *item;
SellViewController *sellView;
NSString *unique;
}

@property (nonatomic, retain) IBOutlet UITextView *itemDescription;
@property (nonatomic, retain) IBOutlet Item *item;
@property (nonatomic, retain) SellViewController *sellView;
@property (readwrite, assign) NSString *unique;

-(IBAction) sellItem : (id)sender;
@end


Item.h

@interface Item : NSObject {
NSString *itemName;
NSString *itemDescription;
int *itemPrice;
NSString *unique;
}

@property (nonatomic, retain) NSString *itemName;
@property (nonatomic, copy) NSString *itemDescription;
@property (readwrite, assign) int *itemPrice;
@property (nonatomic, retain) NSString *unique;

-(id)initWithName:(NSString*)name description:(NSString*)desc price:(int*)price;



fenrus110
Oct 29, 2008, 05:53 PM
Your Item is an IBOutlet when it is not. Though, not sure if that does anything...

Niiro13
Oct 29, 2008, 06:14 PM
Don't IBOutlet the item.

Other than that, it should work. I use it all the time and that's pretty much how I pass the item (except I don't use IB).

Lakario
Oct 29, 2008, 06:20 PM
If you'll look at my first code block you'll see that I am in fact doing that:


if(self.itemView == nil) {
ItemViewController *viewController = [[ItemViewController alloc] initWithNibName:@"ItemViewController" bundle:[NSBundle mainBundle]];
self.itemView = viewController;
[viewController release];
}

[self.itemView setItem: item];
[self.navigationController pushViewController:self.itemView animated:YES];

Lakario
Oct 29, 2008, 06:23 PM
I've tried removing IBOutlet, but that hasn't made any difference with the problem I have been experiencing.

fenrus110
Oct 29, 2008, 06:23 PM
we're talking about this
@property (nonatomic, retain) IBOutlet Item *item;

Item extends NSObject

Lakario
Oct 29, 2008, 06:29 PM
we're talking about this
@property (nonatomic, retain) IBOutlet Item *item;

Item extends NSObject

Aye as was I.

firewood
Oct 29, 2008, 07:45 PM
The trouble is, no matter how many different ways I try to set the Item property of ItemViewController, it always end up null when the view loads.

1. The view controller object may not exist until it loads, so trying to set a item property in a non-existant object is probably futile.

2. Instead of trying to reach inside a view controller and muck with its item's properties, you could have the view controller check an external data model object and update its own items or views accordingly. I think that would be closer to the MVC paradigm.

.

Lakario
Oct 29, 2008, 07:49 PM
1. The view controller object may not exist until it loads, so trying to set a item property in a non-existant object is probably futile.

2. Instead of trying to reach inside a view controller and muck with its item's properties, you could have the view controller check an external data model object and update its own items or views accordingly. I think that would be closer to the MVC paradigm.

.

Would it be sufficient to have the view ask the app delegate for the item currently selected by the user at the top of the navigation? The problem with that approach is that these views can be reached in a number of ways but I need them to function the same regardless. I don't want to explicitly call a parent object in the view's definition just to retrieve a value, rather I'd like the object that creates the view to set its properties.

jesse.armand
Oct 30, 2008, 04:22 AM
Where did you get the (self.itemView.item == nil) ?

Lakario
Oct 30, 2008, 08:32 AM
Where did you get the (self.itemView.item == nil) ?

Pardon? That is not my part of my code I was simply stating that it is always nil no matter what I set it to.

PhoneyDeveloper
Oct 30, 2008, 09:06 AM
Can you show the declaration for the root view controller's property setItem? The IBOutlet text in your properties, while not idiomatic, probably won't cause a problem.

Lakario
Oct 30, 2008, 10:28 AM
Can you show the declaration for the root view controller's property setItem? The IBOutlet text in your properties, while not idiomatic, probably won't cause a problem.

RootViewController does not define setItem, ItemViewController does. iPhoneHelloWorldAppDelegate contains an NSMutableArray of Items and I retrieve the relevant item on the draw and click events of the table cell within the RootViewController.

iPhoneHelloWorldAppDelegate.m (excerpt)

@property (nonatomic, retain) NSMutableArray *items;


ItemViewController.m (excerpt)


@interface ItemViewController : UIViewController {
IBOutlet Item *item;
}

@property (nonatomic, retain) IBOutlet Item *item;


I just realized that I was somewhat misunderstanding my program flow originally. I previously thought the RootViewController contained my Item array when in fact it was the AppDelegate that did. (I followed a tutorial for the initial pieces of this application). That being said, should I be asking the AppDelegate for the Item reference rather than trying to pass it into my view? That would be a better MVC architecture (assuming the AppDelegate is my Controller and the ItemView is, well, the View), but that comes back to the issue of wanting to make my Views more abstract. What if I have two controllers that could bring the user to the ItemViewController nib? (Or does the iPhone SDK even want you to have more than one controller per application?). My only experience with MVC is in the J2EE framework where your servlet acts as the controller and it is perfectly acceptable there to have multiple controllers (servlets).

I think what is most confusing to me is the fact that I have no problem setting my ItemViewController's UITextView.text property from the RootViewController, but when I try to pass a whole object (like my Item) from one view to the next I lose the object. Why would I be able to pass a string without any difficult but be completely unable to pass a custom object?

Eventually this application will have a base Game object that defines a player and each Player has a set of Items with their own properties. Additionally, other Players (not the user) will have their own Item set as well. That being said should I move in the direction of having a PlayerController, an ItemController, an XYZController, etc that is all defined within my AppDelegate? If that's the case then I believe it would be prudent to modify the application at its root.

Thanks guys!

Lakario
Oct 30, 2008, 11:31 AM
Well the good news is I figured out what was wrong and my Item is being set correctly now. The bad news is how retarded the problem was. Maybe someone can explain this behavior because I don't really follow it...

My ItemViewController defined an Item object and referenced it in the File's Owner. Every time the view loaded the Item object in my View was overwriting anything I had set before loading the View. Why would that happen?

What a friggen waste of 3 days...