Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to message superview in Objective C

I am new to Objective C and Cocoa. I just don't get it how to message the superview of an UIView. I can't get it work. Here is what i tried so far:

In my MainView i have a method named resetDrawType:

- (void) resetDrawType {
   self.drawType = foo;
}

Also in the MainView i create a subview and add it to MainView:

mySubView *mySubView = [[mySubView alloc] initWithFrame:CGRectMake(foo, foo, foo, foo)];
[self addSubview:mySubView];
[mySubView release];

Then when the subview finished its drawing i want to send the message resetDrawType to its superview, which is the MainView.

I tried this

 [(MainView*)[self superview] resetDrawType];

and

 [(MainView*)self.superview resetDrawType];

…what didn't work. I learned about Informal Protocols so i added this code to MainView.h

 @interface NSObject ( resetters )
    - (void) resetDrawType;
 @end

But still nothing. Next i found out about this selector thing and tried this in the subview:

 if ([self.superview respondsToSelector:@selector(resetDrawType:)])
    [self.superview performSelector:@selector(resetDrawType) withObject:nil];

It also didn't work. What am I doing wrong? Thanks for your help.

like image 601
rainerkohlberger Avatar asked Feb 11 '09 17:02

rainerkohlberger


2 Answers

You shouldn't have a subviews tell its superview much of anything. You should make the superview a delegate of your view class.

// MainView
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(...) delegate:self];

Then save the delegate to an instance variable declared by id delegate. When you finish drawing:

// MyView
- (void)doDrawing {
  drawStuff();
  [delegate didFinishDrawingView:(MyView *)self]
}

Now back in your MainView, implement this method

- (void)didFinishDrawingView:(MyView *)aView;

to do what you want.

The point of all this is so that the small classes at the fringe of your app (like a small subview) shouldn't need to know how the large classes above them work. This setup allows the view to communicate up the chain, but with a message that conveys its own status instead of a message that instructs other object to do something specific. This is the way Cocoa is structured so that classes can be easily reused and their events can be repurposed however you need them to be.

Your superview should know what to do when its subview finishes. The subview should just let people know its finished.


Declare an instance variable in your subview class's header like this:

id delegate;

Write an initiailizer for your subview class that looks like this:

- (id)initWithFrame:(CGRect)frame delegate:(id)aDelegate {
  [super initWithFrame:frame];
  delegate = aDelegate;
  return self;
}

Now you have an initializer that will accept a delegate, saves that delegate, and allows you to then call methods on it.

like image 100
Alex Wayne Avatar answered Oct 08 '22 23:10

Alex Wayne


Well firstly in Objective-C there's no need to cast to a specific class to send it a message. E.g you can just do;

[self.superview resetDrawType];

Providing the parent view has the following function;

- (void) resetDrawType {

}

Then this should work correctly. There's no need to use informal protocols.

Also your selector testing is wrong because it does not match the definition of the "resetDrawType" function. @selector(resetDrawType:) tests for a function named "resetDrawType" that takes on parameter, which yours does not.

This is how you would test for the function above;

if ([self.superview respondsToSelector:@selector(resetDrawType)])
    [self.superview performSelector:@selector(resetDrawType)];

(Instead of performSelector you could also send the message directly).

like image 42
Andrew Grant Avatar answered Oct 08 '22 23:10

Andrew Grant