Reputation: 5923
I'm trying to call an instance method which is in my UIViewController from within a UIView. In my UIViewController I have something like:
-(void) test {
NSLog(@"test");
}
In my UIViewController, I create an instance of my UIView like so:
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
In my draggableView
, I then want to call the test
instance method. How do I do this without creating a new instance of the UIViewController?
I have tried this, but it doesn't seem like a very elegant solution and I get an error "No visible @interface ..."
Upvotes: 1
Views: 865
Reputation: 86135
View does not have default method to access its view-controller object. You need to pass the view-controller object into the view object yourself. Typical way to do this is making a property.
@class ViewController;
@interface DraggableView : NSObject
@property (readwrite,nonatomic,assign) ViewController* theOwnerViewController;
@end
@implementation DraggableView
- (void)testCallingOwnerViewControllerMethod
{
[self.theOwnerViewController test];
}
@end
You need to set the theOwnerViewController
after you created the DraggableView
object.
- (void)loadView
{
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
draggableView.theOwnerViewController = self;
//...extra view setup.
}
Use assign
to avoid retain-cycle on the property.
You can do this by above pattern, but as you noticed, you need to know and forward-declare the owner view-controller class' name from its view (which is sub-node of the VC). Usually This is bad design choice because it's easily makes circular dependency (or backward dependency), which usually creates tight-coupling.
Instead, you can use delegate pattern to avoid circular dependency issue.
@protocol TestDelegate
- (void)test;
@end
@interface DraggableView : NSObject
@property(readwrite,nonatomic,assign) id<TestDelegate> testDelegate;
@end
@implementation DraggableView
- (void)test
{
[self.testDelegate test];
}
@end
You need to set the testDelegate
after you created the DraggableView
object.
@interface ViewController<TestDelegate>
@end
@implementation
- (void)test
{
// do something.
}
- (void)loadView
{
draggableView = [[DraggableView alloc]initWithFrame:CGRectMake(20, 190, 280, 280)];
draggableView.testDelegate = self;
//...extra view setup.
}
@end
In this case, you don't have to know the class name of the view object before you create. Any class which conforms TestDelegate
protocol can be used, and now the view and VC are loosely-coupled via the protocol.
Upvotes: 3