简体   繁体   中英

Call instance method in ViewController from View

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 ..."

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.

Delegate pattern

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM