views:

667

answers:

2

In a word, how?

I have a view controller that creates a few custom objects. One of those objects needs to call a method back in the controller. The object looks like it wants to call a class method in the controller, which might be fine, except that class in the controller needs to call an instance method in the controller, and it doesn't seem to want to do that. Does that make sense?

If not, here's pseudo code:


ViewController.m

#import "customObj.h"
-(void)viewDidLoad{
  foobar=@"string";//declared in ViewController.h
}
-(void)createObj{
  foobar=@"different string";
  customObj *customObjInstance=[[customObj alloc] init];
}

---

customObj.m

#import "ViewController.h"
-(void)callBack{
  [ViewController createObj];
}

Okay, so when callBack runs, it errors, saying it's looking for +createObj (not -createObj). I can change createObj to a class method, but then it has a problem setting foobar because foobar was initialized in -viewDidLoad, and I can't change that to +viewDidLoad. I could maybe move foobar out into a class method, but then how do I call it? Instead of self, do I refer to [ViewController ...]? I don't think that works.

My guess is I'm missing some basic concept and it's not anywhere as difficult as I'm making it. I am indebted to anyone who can straighten me out.

Thanks much.

+5  A: 

There's no single correct answer; it depends on how your custom object interacts with the controller. Most UIKit views use a "target-action" pattern for communicating with the controller, while a lot of model objects use the delegate pattern. Which one you use depends on the specifics of your controller and your custom object.

However, mechanically, what you'd probably need to do is pass in a pointer to your ViewController when you create the customObj via a custom initializer, like so:

customObj *customObjInstance = [[customObj alloc] initWithController: self];

Be sure it makes sense for your customObj to be tightly coupled to your controller if you do this.

John Calsbeek
Hmm... Thanks. I've passed pointers in the past, and it seems like such a kluge that I couldn't imagine it was the right way to do it. So an object has no reference to the object that created it? Other languages I've worked with have something like 'parent' which is distinct from the super class of the object. If I have a uiview object that creates a uitableview object, that tableview object doesn't have any reference to the uiview instance that spawned it? That omission is one that I keep coming up against.Thanks again.
Eric Christensen
Views have the concept of a `superview`, which is the view that they are contained in—but there is no general concept of a "creating object." Typically, you decide what relationship the controller object has to the model object. In your case, for instance, you might decide that a customObj instance has need of another object to create more objects for it, and you might model that using a delegate (which is, at heart, a pointer to another object, but it's more generic).There are all kinds of ways to do it, and the best way depends on your specific circumstance.
John Calsbeek
If you want an object to have a "parent," you give it one. In general, I don't find I have a need for such specific coupling.
Chuck
+3  A: 

You may have thrown me with you various mentions of class to instance to class, but if all you mean is that the controller needs to create objects which can call the controller (to create more of the same), that i can help you with.

I do this quite a bit, using - as john has mentioned - the delegation pattern:

Define a protocol for the calls from the object to the controller: callBack

//  CallBackDelegate.h


#import <Foundation/Foundation.h>

@protocol CallBackDelegate<NSObject>
- (void)callBack;
@end

in the header file for the controller i import the protocol

#import "CallBackDelegate.h"

and specify that the controller implements this protocol:

@interface MyViewController : UIViewController < CallBackDelegate > 
{ ...

meanwhile in the custom object class header also import the protocol

#import "CallBackDelegate.h"

and add an instance member which conforms to the protocol:

id<CallBackDelegate> delegate;

and a property, which must be assign not retain or you will have circular retains, the controller and the custom object would be retaining each other, which would mean they would never deallocate

@property(assign) id<CallBackDelegate> delegate;

(this member doesn't have to be called delegate)

Then make sure that when your view controller creates the custom object it sets it self as the delegate

customObject.delegate = self;

Then in your custom object you are safe to do this:

[ delegate callBack];

hope that helps, mat

if you search the apple sample code you'll find examples for something like:

[ delegate touchesEnded:touches withEvent:event];

of course if you want the method to pass you an id to the created object, the method doesn't need to return (void) as in my example

if you want to you can write an init method which takes the delegate as john also suggested

customObj *customObjInstance = [[customObj alloc] initWithController: self];

inside initWithController the controller you pass in would need to be assigned as the delegate

compound eye
Indeed, delegation is a really common pattern used across a lot of objective-C - and protocols are the key to making it easy to do this.
Kendall Helmstetter Gelner