Second View changes variables from the first


I wanted an app with two pages, i’ll use the hypnotizer sample as an example.
If i set the stroke value as a variable in hypnosisView, i then want the second tab to have a slider that changes the stroke value.
I have got sliders to change values before but that was all in the same window with only one object in the app.

I was wondering what the basic concept for this example would be?


You mean two views, where one view communicates to the other?

So you want one view to change a value that must be communicated to the other view?

If I were to do this quick-n-dirty – not reusable or good design here! – I would try to make use of the view controller’s tabBarController to get my tab bar, then from there get my other view controller, and call an appropriate method to set the data.

If I were to do this cleanly and Apple-y – that is, following Objective-C and Cocoa patterns – I would make my second view controller adopt a custom delegate protocol, and make it a delegate of the first. The protocol would have the method(s) necessary to pass data. So the first controller wouldn’t need to know anything special about the second controller, it just needs a reference to a delegate. In partial code:

[code]@protocol SizeSetter

  • (void)sizeDidChange:(NSInteger)newSize;

// View Controller 1
// has an ivar called sizeSetter, which is assigned View Controller 2, maybe in appDidLoad:
// id sizeSetter;

  • (void)actionMethod:(id)sender
    NSInteger newValue = … // get newValue from sender or equiv IBOutlet
    [sizeSetter newValue];

// View Controller 2
@interface MyViewController <UIViewController, SizeSetter>

// it’s implementation includes this method

  • (void)sizeDidChange:(NSInteger)newSize
    // store the newSize as a property
    // call setsNeedDisplay on the view if you need to update the drawing

I hope I explained it clearly enough.

There may be other ways to do this, and I look forward to anyone else’s thoughts.



Here’s another option for consideration…

The view that makes the changes would trigger with:

NSNumber *stroke = [NSNumber numberWithInt:42];
NSDictionary* dictionary = [NSDictionary dictionaryWithObjectsAndKeys: stroke, @"stroke", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"HeyTheStrokeValueChanged" object:nil userInfo:dictionary];

And then any interested parties (views) can register their interest - init or loadView for example

// Register our interest in any object that posts these notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(strokeValueChanged:) name:@"HeyTheStrokeValueChanged" object:nil];

which would trigger

	NSDictionary* userInfo = [notification userInfo];
	NSNumber *strokeValue = [userInfo objectForKey:@"stroke"];
	NSLog(@"The other view changed the stroke to %@", strokeValue);

and you should deregister when no longer interested (dealloc for example)

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"HeyTheStrokeValueChanged" object:nil];



Ok thanks guys. Those are both great suggestions. I’ll try both and report back on how it goes.



I had trouble implementing custom delegates, but notifications worked very well with the value being passed as a dictionary.



Glad it worked out - I’d persevere with custom protocols as well though as they can be incredibly useful.



I like the NSNotification idea.

If you register your NSNotification in loadView would it be best to un-register in viewDidUnload just to be symmetrical?



I would deregister in both viewDidUnload and dealloc as they can both be triggered independently of each other.

viewDidUnload will be invoked in a low-memory situation without dealloc and dealloc can be triggered without viewDidUnload.