views:

91

answers:

6

Hi

In my iPhone project I have a UIViewController in which I add an instance of a subclass of UIView. From this instance I need to communicate back an integer to my view controller. My current solution is to send a message from my instance to my App Delegate which sends a message to the view controller. It works, but it feels a bit messy.

Is there anyway I can send a message straight back to the view controller?

I would love to be able to do something like [super doSomething:123];

Any ideas?

Thanks

+1  A: 

Um, I'm not sure I understand your problem correctly. You have a class derived from UIView which needs to send a message to another class derived from a UIViewController. It sounds like you are creating the UIView instance programmatically. Is there any reason my you could not have a property on the UIView which refers to the UIVIewController and just use that to send it a message directly.

You cannot use [super ...] because the super of your UIView derived class would be UIView.

Or am I miss-understanding the issue :-)

Derek Clarkson
Hi Derek. As you correctly got it, I'm programmatically adding a view from my view controller. I have some properties that I could read, but I currently don't have any loop (timer driver) that could catch the change in the property. Think I will try digging in to Dan's reply, but thanks for the super explanation.
Structurer
Hmm, just a thought, but I was reading about NSNotification and using notifications to allow objects to track changes in other objects. I haven't used it yet, but it may be something that can help. Do a google search for NSNotification and a number of articles will pop-up about using notifications.
Derek Clarkson
Ahh, I just scrolled down and read Dan's post :-)
Derek Clarkson
A: 

Simply add an outlet to your UIView subclass, connect it to its view controller in Interface Builder, and call your method on that. Here’s how that might look:

MyUIView.h:

@interface MyUIView : UIView
{
  UIViewController *viewController;
}
@property (assign) IBOutlet UIViewController *viewController;
@end

MyUIView.m:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  [[self viewController] setTitle:@"Hello from MyUIView"];
}
Todd Yandell
A view's superview is very unlikely to be a `UIViewController`, as that's not a view.
Graham Lee
Haha, good point. Looks like I didn’t think it through very well. I’ll remove that part so this answer is still somewhat useful.
Todd Yandell
This answer is actually correct, though lacking in details.
bbum
Right you are. I’ve added an example and a bit more detail. This answer was originally a footnote on an inaccurate answer which I removed. Hopefully it’s more useful now.
Todd Yandell
+1  A: 

If I understand correctly, you want to send a message from your subclass of UIView to the view controller.

That means your subclass of UIView needs to have a property or ivar which is the view controller. The easiest way to do this is to add it as an outlet and connect it to the view controller in the nib file.

JeremyP
Thanks Jeremy but I'm adding the view programmatically and don't have a nib.
Structurer
You don't need a nib to make a connection between objects. Anything that can be done in IB can also be done in code.
bbum
A: 

Generally you should not go via the app delegate. Having a typed pointer link is also less than ideal.

The optimal way of communicating - Apple does it like this as well - is to create a delegate protocol. When creating the view controller you pass a pointer to the delegate as id . Then when it gets to sending the message you ask the delegate:

if ([delegate respondsToSelector(didFinishSomething:)])
{
  [delegate didFinishSomething:info_to_pass];
}

If you want to be extra-sophisticated then you can also add a pointer to the calling class instance. Like:

[delegate myViewController:self didFinishSomething:info_to_pass];

This way you always know what kind of class the message is coming from.

If there is more than one place that needs to be notified of a change, then instead of delegation you will use notifications.

Dr. Touch
Hi Dr Touch. Any reason why I should not go through the app delegate (more that the obvious extra code and spaghetti links...).
Structurer
+1  A: 

This is the kind of thing that NSNotificationCenter was provided for. Once you get handy with sending and receiving notifications, your message-passing gets a WHOLE lot simpler.

One of the classic things people confront is how to get a pointer to the object they want, in order to tell it about something. How do I, for instance, tell the ViewController two slots back up the UINavigationController stack that the user just changed this data field? So you dig into the stack, offset back by some magic number of elements in the stack, build public setters on the fields you want talk to... It's super cumbersome.

Compared to registering as a notification receiver in one place, and then firing a notification in some complete other place when the data changes. It's kind of magical, after doing all the "dig through the view hierarchy" work.

Dan Ray
Thanks Dan. I will look into it tomorrow. Guess it's similar to the notifications for handling multitasking in iOS 4? Will come back when I have tried it.
Structurer
Notifications are comparatively slow to invoking a method. And it creates an informal link that will be easily forgotten or hard to discover when someone new looks at the code. A delegate like pattern is faster and more straightforward.
bbum
Matter of opinion, I guess @bbum. I find the notification approach MUCH easier to think through from the developer's standpoint. I'd rather show a new Cocoa developer how to work NSNotificationCenter than how to build a delegate interface.
Dan Ray
Not a matter of opinion. Notifications are not to be used to create formal relationships between objects. Notifications are for casual relationships where the notification receiver may or may not exist (or there may be many). In this case, a formal relationship -- a reference between -- would be the recommended pattern.
bbum
Furthermore, notifications can very quickly spiral out of control. I've debugged dozens of cases where notification A triggers notification B which triggers C which triggers A ... etc. Notifications are imprecise, difficult to debug, and create a barrier to entry as new engineers work with a codebase. They are extremely useful when used carefully, sure, but abuse leads to busted code.
bbum
Hi again. Tested it in two ways: without userInfo and with userInfo. Both works fine and takes away the use of the app delegate and double methods (once in app delegate and once in my view controller). So I'm happy! To make the code easier to read I have added comments close to where I send the notification and add an observer. For those who would like to try this, read more here http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
Structurer
More info here (sorry but link made the field too long) http://www.slideshare.net/360conferences/nsnotificationcenter-vs-appdelegate
Structurer
A: 

In my iPhone project I have a UIViewController in which I add an instance of a subclass of UIView.

This implies that you have both a reference to the instance of the UIView subclass and the UIViewController in the same scope. I.e. something equivalent to:

UIViewControllerSubclass *myViewController;
UIViewSubclass *myView;

(It doesn't matter if they are actually instance variables or, even, globals)

And once those two variables are initialized, somewhere you do something like:

myViewController.view = myView;

In your UIViewSubclass, add a property that points back to your UIViewControllerSubclass:

@property(assign) UIViewControllerSubclass *myController;

Then, when you do the above assignment, add:

myView.myController = myViewController;

From there, messaging your controller from your view is easy:

[self.myController yoManHereIsAnInt: 42];

Note that I used assign instead of retain because the controller already retains the view. If the view were to also retain the controller, you would have a cycle that would eventually lead to a leak.


No super about it. super is entirely related to the inheritance hierarchy of your Objective-C classes. What you are asking has nothing to do with inheritance and everything to do with how the various instances of objects in your application are connected together.

bbum
Hi bbum. Sorry for using the super in a wrong way. I guess I could have expressed it like [parent doSomething:123]. What I have is not exactly what you describe above. I create the instance of my subclass within the view controller (therefore the "parent"). I need it in the view controller as the view controller manages when, where and at what "level" (bringSubviewToFront) should be showed. But I learned something new from your answer, so thanks!
Structurer