Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jcohen2j

macrumors newbie
Original poster
Dec 29, 2009
4
0
NY
Hi folks,

I'm learning how to program for fun and to better understand what programmers have to deal with at work (I'm a UX Designer). I just finished reading Learning C on the Mac, Learning Objective C 2.0, Beginning iPhone Development, and I'm trying to build my first iPhone app. I'm extremely stuck on what I assume is a typical noob problem: passing values between controllers.

In the app I'm making, I have three controllers which inherit from the same parent controller. For example- "soundSelectorRight : SoundSelectorViewController" Each of these three inherited controllers has its own nib and a table populated by values in a property list. The string in the selected row appears in a label just above the tab bar, which is used to navigate between views (and their associated controllers). There are three labels, one per tab, and it would be great if the labels could show the selected row in all three tabs. You can probably guess where this is going...

How can I make it so selecting a new row in the first tab updates a label in the third tab?

I tried @class stuff, but I've been reading up on it, and I'm starting to think that's not the way. Any thoughts would be really appreciated... thanks guys...
 
You would have to create a property for the object that you want to change you could then for example in the third class call the first class such as firsclass.object.value = the value. this should allow you to set the object in the first class from the third class and so one.
 
Your application is running three view controllers at once? Each view controller represents one tab in the tab bar controller? Is that right?

Each view controller is responsible for displaying three separate labels. Is that right?

As far as handling which strings are currently selected, you might want to consider delegation. When you initialize the three view controllers, you could point them to the same delegate (your application delegate, perhaps). This delegate object could have an NSArray for your three strings. When your view controller first displays the labels, it "calls back" to the delegate object to ask what to display. Anytime a view controller changes the selected string, it "calls back" to the delegate to tell it that it just changed its string (and gives it the new value).

When the value is changed, you probably want to post a notification. This will let you "reach across" view controllers. The first view controller could tell its delegate what the new string should be, then it posts a notification (to the whole application) that tells the other two view controllers to reach back to their delegate and retrieve the strings again.

This might sound little abstract, but try looking up delegation and notifications in the "Cocoa Design Patterns" documentation.
 
Thanks so much guys - I'll give these tips a shot on the commute home tonight and let you know how it goes.
 
There are some haphazards with using the appdelegate. You may want to read up on it as it is not the best practice to use only the app delagate or singletons according to Standfords iphone class.
 
I do not think using the application delegate has to be dangerous if you use it just in its capacity as an arbitrary delegate object. You just make the application delegate conform to the same protocol that your view controller delegate is expecting. If you initialize the view controllers in your application delegate, you can just assign the delegate right there.

For instance, if the OP needs to access the string array in one particular view controller, there could be something like:

Code:
NSArray *delegateStringArray = [[self myDelegate] stringArrayForFirstViewController: self];

[self doSomethingWithDelegateStringArray: delegateStringArray];

It doesn't really matter that the delegate object being called is also the application delegate -- the view controller just cares that it conforms to the protocol.

If, on the other hand, you were to do this:

Code:
NSArray *delegateStringArray = [[UIApplication sharedApplication] delegate] stringArray];

[self doSomethingWithDelegateStringArray: delegateStringArray];

I think this is dangerous, because it is not a good idea to assume that the "stringArray" will always be in your application delegate.
 
Thanks again, no luck yet, but so far I only gave KoolStar's first post a good shot. I read through the links Dejo posted, and next up I'll try an app delegate approach. I'm obviously not getting something fundamental about how OOP, or maybe just Objective-C, works...

I have a ViewController, SoundSelectorViewController, which has three children: soundSelectorLeft, soundSelectorDown, and soundSelectorRight. Each child controller instance has a nib, assigned to a tab item, and are exactly the same -- there's no unique code specific to any of the child controllers.

My approach was to @class all three child controllers in the parent. In SoundSelectorViewController.h is "@class soundSelectorDown", then further down "soundSelectorDown *referenceToSoundSelectorDown", and in SoundSelectorViewController.m, I #import "soundSelectorRight.h". When a row is selected in one view, a UILabel showLeft receives a string with the row text. I set showLeft in the @class representation of all three controllers to the row text, which doesn't work:

Code:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	
	NSUInteger section = [indexPath section];
	NSUInteger row = [indexPath row];
	NSString *key = [categories objectAtIndex:section];
	NSArray *categorySection = [[categoriesSounds objectForKey:key] objectAtIndex: 0];
	NSString *rowValue = [categorySection objectAtIndex: row];

	
	NSString *soundLeftString = [[NSString alloc] initWithFormat:
									  @"%@", rowValue];
	
	showLeft.text = soundLeftString;
	
	referenceToSoundSelectorLeft.showLeft.text = showLeft.text;
        referenceToSoundSelectorDown.showDown.text = showLeft.text;
        referenceToSoundSelectorDown.showRight.text = showLeft.text;
}

Here's a screencast of the app in action. (the labels in each view should be identical) http://www.screencast.com/users/Jon...ng/media/2f41d2f8-dcf3-46d7-82c0-a40bc096d79c

If you guys could point me toward the concept I need to learn to understand this stuff, it would be extremely helpful... thanks again.
 
I do not think using the application delegate has to be dangerous if you use it just in its capacity as an arbitrary delegate object. You just make the application delegate conform to the same protocol that your view controller delegate is expecting. If you initialize the view controllers in your application delegate, you can just assign the delegate right there.

For instance, if the OP needs to access the string array in one particular view controller, there could be something like:

Code:
NSArray *delegateStringArray = [[self myDelegate] stringArrayForFirstViewController: self];

[self doSomethingWithDelegateStringArray: delegateStringArray];

It doesn't really matter that the delegate object being called is also the application delegate -- the view controller just cares that it conforms to the protocol.

If, on the other hand, you were to do this:

Code:
NSArray *delegateStringArray = [[UIApplication sharedApplication] delegate] stringArray];

[self doSomethingWithDelegateStringArray: delegateStringArray];

I think this is dangerous, because it is not a good idea to assume that the "stringArray" will always be in your application delegate.

The second way is how i see that most people tend to use the app delegate so that is why i had warned against that. Otherwise your first way makes sense for some specific items.
 
Thanks again for all your help - I solved the problem and achieved the functionality I wanted by rebuilding the app without a tab bar and programming three switches -- the user activating one to true sets the other two to false -- to map to each direction.

I'm still confused about whether it's possible to pass values between controllers which aren't in a stack. While there may be a way to pass values between controllers in a tab bar, now I realize this design pattern is primarily for mapping different modes of functionality on top of the same data.
 
I'm still confused about whether it's possible to pass values between controllers which aren't in a stack.
It most certainly is. It's just that there are a number of approaches to choose from to achieve this, including using the app delegate, using a singleton, connecting the two view controllers via an IBOutlet or even an ivar, using NSUserDefaults, ...
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.