Trigger a Method in Uiviewcontroller from Its View

Trigger a method in UIViewController from its View

You can do something like this

CustomView.h

#import <UIKit/UIKit.h>
@protocol CustomViewDelegate <NSObject>

-(void)didButtonPressed;

@end

@interface CustomView : UIView

@property (assign) id<CustomViewDelegate> delegate;

@end

CustomView.m

#import "CustomView.h"
@implementation CustomView

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor whiteColor];

//[self addSubview:titleLbl];
UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(100, 100, 100, 50);
[button addTarget:self.delegate action:@selector(didButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"pressMe" forState:UIControlStateNormal];
[self addSubview:button];

}
return self;
}

in your ViewController.m

-(void)loadView
{
[super loadView];
CustomView *view = [[CustomView alloc]initWithFrame:self.view.bounds];
view.delegate = self;
[self.view addSubview:view];

}

How to call a method/an action inside UIViewController from custom UIView?

Use protocol/delegate:

protocol TapHandler {
func tapped()
}

class MyView: UIVieww {
weak var tapHandler: TapHandler?

/// button tap handler
@obj func yourTapFunctionInsideView() {
tapHandler?.tap()
}
}

class MyViewController: UIViewController, TapHandler {
var view: MyView?

override func viewDidLoad() {
super.viewDidLoad()
view?.tapHandler = self
}

func tapped() {
/// tapped
}
}

How Do I call a method from a view contained in a view controller ?

I think you can set up a protocol in your Subview, which can be implemented by your ViewController

Your SubView.h

@class SubView;

@protocol SubViewDelegate <NSObject>
- (void)actionToPromoteToViewController: (NSString *)exampleString isSelected:(BOOL)exampleBool;
@end

Then, in your ViewController.h:

@interface MainViewController : UIViewController <SubViewDelegate>

and your ViewController.m, implement the method.

- (void)actionToPromoteToViewController: (NSString *)exampleString isSelected:(BOOL)exampleBool{
// Method Implementation

}

Call instance method in ViewController from View

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.

Call UIView method from ViewController

Create a new variable chart in your ViewController and add this chart as subView to the view outlet connected from xib

Your ViewController class would look like below:

class DetailDashboardViewController: UIViewController {

@IBOutlet weak var chartView: UIView!
var chart: UIView!

override func viewDidLoad() {
super.viewDidLoad()

if index != 3{
chart = NSBundle.mainBundle().loadNibNamed("BarChartDashboard", owner: self, options: nil)[0] as? BarChartDashboard
}
else{
chart = NSBundle.mainBundle().loadNibNamed("LineChartDashboard", owner: self, options: nil)[0] as? LineChartDashboard
}

self.chartView.addSubView(chart)
self.chart.frame = self.chartView.bounds
runQueries(2)
}

private extension DetailDashboardViewController {

func runQueries(period: Int) {

self.query(false, periodIndex: period){ (success) -> Void in
if success {
// do second task if success
dispatch_async(dispatch_get_main_queue(), {
if self.index != 3{
(self.chart as! BarChartDashboard).setChart(self.yAxis, values: self.xAxis)
}
else{
(self.chart as! LineChartDashboard).setChartData(self.yAxis, yAxisMax: self.xAxisMax, yAxisMin : self.xAxisMin)
}
})
}
}
}

How to call from a Popover a method of the main view controller?

You are trying to call the method from the new instance of your ViewController. Instead, you need to declare a delegate property in the Popover VC and pass the original parent VC within prepareForSegue:sender: method as a delegate for your Popover VC.

Call method in another View Controller, but not segue to it?

Using Swift 3

Before I provide a solution I'll point you to @Paulw11's comment, he's 100% correct. The proper convention is to pull your connectivity logic out of your view controllers. The only code you should have in your view controllers is the code necessary to display your view. Connecting to a server and managing the result has nothing to do with actually presenting the resulting data in the view.

If you really felt compelled to call a function directly from another view, you shouldn't do it by creating a new instance of your view controller. Rather, you should just get the existing instance like this:

let app = UIApplication.shared.delegate! as! AppDelegate
if let viewControllers = app.window?.rootViewController?.childViewControllers {
viewControllers.forEach { vc in
if let view = vc as? AnotherViewController {
view.downloadIt()
}
}
}

Personally, I'd recommend pulling this logic out of your view controller either way. If you're trying to keep things minimal, or if this is the only web service call you are making, you could simply do something like this:

Add a new Swift file with a protocol and an extension to that protocol:

protocol Downloadable : class { }

extension Downloadable {

func downloadStuff() -> String {
// Add your download logic here
return "downloading"
}
}

Then, in any view you want to be able to use this download function just add the protocol to your View Controller like this:

class ViewController: UIViewController, Downloadable {}

Then you can very easily get your downloaded data like this:

@IBAction func handleDownloadTapped(_ sender: UIButton) {
let result = downloadStuff()
print(result)
}

Again, you shouldn't get in the habit of doing this as it can get messy if you are working with a few different api calls.

The best practice is to create a class that contains your web service stuff, I personally like the objc.io approach. You can find a tutorial here.

https://talk.objc.io/episodes/S01E01-networking

Basically you'll create a service like this

public typealias JSONDict = [String: AnyObject]

struct Resource<A> {
let url: URL
let parse: (NSData) -> A?
}

let url = URL(string: "https://url")!

let myResource = Resource<[JSONDict]>(url: url) { data in
let json = try? JSONSerialization.jsonObject(with: data as Data, options: [])
return json as? [JSONDict]
}

final class Connect {
class func load<A>(resource: Resource<A>, completion: @escaping (A?) -> Void) {
URLSession.shared.dataTask(with: resource.url) { (data, _, _ ) in

if let data = data {
completion(resource.parse(data as NSData))
} else {
completion(nil)
}
}.resume()
}
}

And you can call it wherever you need to like this:

Connect.load(resource: myResource) { result in
// do stuff with result
}

I hope this was helpful to someone

Call method of presenting viewcontroller from modal

You need to create a delegate of ContentViewController and in that delegate you need to add this method goToContent.

Now when you are logged in successfully, you need to call this delegate method. It will work.



Related Topics



Leave a reply



Submit