I don't know if it is possible, but I would like to call a view controller's method in a class object. I have method like this in my view controller's .m file:
-(void)showLeaderBoard
{
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil){
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated: YES];
}
}
I would like to call that method in a SKScene file.
One way to do this is called delegation. In a nutshell, you allow the view controller to be the delegate on the object, so when the object wants to do something the view controller does, it can tell its delegate (the view controller) when to do it.
Step 1: Create the delegate property on the object (in the objects .h file):
// be sure to import the view controller's header here
#property (nonatomic, retain) YourViewControllerClass *delegate;
Step 2: When you create the object in your view controller, set the view controller as the objects delegate:
SKScene *theScene = // however you create your scene object here
theScene.delegate = self;
Step 3: Expose whatever method you want the object to call in the view controller's header:
- (void)showLeaderBoard;
Step 4: When you want to, tell the object's delegate to do whatever you want it to (inside the SKScene .m file):
[self.delegate showLeaderBoard];
Related
I am having trouble linking up a switch. I understand how to connect the switch as an outlet and have it have actions change the boolean state of a value, but I need the switch to perform an action in a different view controller.
Here's the situation: I have a main table view controller, called View Controller A. I have a second view controller, lets call it view controller B, that controls a menu sidebar (on a regular view controller, not a table view) triggered by a bar item. I want to be able to open up the menu, hit a switch in the sidebar, and have something change in the main table view that is controlled by view controller A.
Is there any way that I can accomplish this? I seem to have no way of accessing or changing the IBOutlets in View Controller A from B. Is there a way that I can have the action in B linked with the switch change the boolean state of a value, and have an action waiting in controller A that will respond to a change in boolean? I am not sure how to solve this problem. Help is appreciated!
You should use delegation pattern. You'll have an action waiting in controller A, but instead of responding to value changed in B the action will be triggered by B when appropriate
ViewControllerB.h
// Create delegate protocol and property
#protocol ViewControllerBDelegate <NSObject>
- (void)switchPressed:(BOOL)switchStatus;
#end
#interface ViewControllerB : NSObject
#property (nonatomic,weak) id<ViewControllerBDelegate> delegate;
#end
ViewControllerB.m
// When switch is tapped, call delegate method if it is implemented by delegate object
- (IBAction)flip: (id) sender {
UISwitch *onoff = (UISwitch *) sender;
if ([self.delegate respondsToSelector:#selector(switchPressed:)]) {
[self.delegate switchPressed:onoff.on];
}
}
ViewControllerA.h
// Conform to ViewControllerB protocol
#import ViewControllerB.h
#interface ViewControllerA : NSObject,ViewControllerBDelegate
ViewControllerA.m
// Set self (VC A) as VC B's delegate
- (void)ViewDidLoadOrSomeOtherFunction {
ViewControllerB *vcB = [[ViewControllerB alloc] init];
vcB setDelegate = self;
}
// Implement delegate method
- (void)switchPressed:(BOOL)switchStatus {
if (switchStatus) {
// Make changes on VC A
}
}
I have a button in mainviewcontroller, when that button is tapped I want to call a method on another view controller. Here below is an image showing my scenario, Green button click to call preview controller VC1 received method without navigation anything. I just need to call that method only!
Declare a method in .h file of VC1 and implement in .m file of VC1
Call that method from MainView Controller ,
Create a NSNotificationObserver in MainView Controller and implement it in .m file of MainView Controller ,
Now when method of VC1 is called and before it returns, fire a PostNotification from VC1 and pass the parameter which you want in MainView Controller.
#RobAu has given correct answer as you can use NSNotificationObserver and call from anywhere.
Other alternate which i have used is using protocol and is very simple.
Just declare a protocol in the child controller. while launching the view put the parent controller as delegate. now call the delegate method from where ever you want from child controller
Here is example which i used (In my case all the child controller was of same kind)
//ChildClass.h file of child class
#protocol updateIndex <NSObject>
-(void)updateMediaId:(NSString*)currentMediaId;
#end
#interface ChildClass : UIViewController
#property NSString *imageID;
#property id updateIndexDelegate;
#end
//ChildClass.m file for child class where you want to call the delegate method
(I called in viewDidAppear method)
-(void)viewDidAppear:(BOOL)animated{
[self.updateIndexDelegate updateMediaId:_imageID];
}
And in ParentClass.m file of parent class use the delegate to self like this
ChildClass *childObject = [[ChildClass alloc] init];
childObject.delegate = self;
and define the delegate method like this
-(void)updateMediaId:(NSString*)currentMediaId {
NSLog(#"%#",currentMediaId);
}
Enjoy coding
I have 2 table view controllers where I on button click on first controller, I am pushing to another view controller.
On the second table view controller, I have a list of items which is checkmarked upon selection. I want to return the selected value to the first view controller.
Also, please let me know how can I use that value in first view controller.
I cant use seagues and the second view controller is generic so I cannot set any of the variables of first view controller in it.
One option would be to create a delegate for that second view controller
In the .h you could declare
#protocol SecondControllerDelegate <NSObject>
- (void)selectionDidFinish:(NSArray*)objects;
#end
#interface SecondViewController : UIViewController
#property(nonatomic, weak) id<SecondControllerDelegate> delegate;
Then in your .m in view will disappear :
- (void)viewWillDisappear:(BOOL)animated{
[self.delegate selectionDidFinish:yourArray];
}
And in your first view controller you'd have to implement this protocol :
in .h :
#interface FirstViewController : UIViewController <SecondControllerDelegate>
and in .m
- (void)selectionDidFinish:(NSArray*)objects{
//Do whatever you want with selected objects
}
and of course when you create your second view controller you'd have to do :
SecondViewController *sVC = [[SecondViewController alloc] init];
sVC.delegate = self;
[self.navigationController pushViewController:sVC animated:YES];
A possible solution is to create a mutable object (NSMutableArray, NSMutableDictionary) in the parent controller and pass it to the child, so the child can modify it and when you are back to the parent - the mutable object will contain the modified values.
Another approach, which requires a little more knowledge is to use a protocol. The basic idea is to create a protocol and a delegate, so the child can "notify" the parent that it chose some values. You can check these examples:
http://www.theappcodeblog.com/2011/04/15/passing-data-between-views-tutorial-using-a-protocol-delegate-in-your-iphone-app/
http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
Please tell me if you need more information.
You can create delegates. Checkout the following link:
http://www.hardcodedstudios.com/home/ryan-newsome/simpledelegatetutorialforiosdevelopment
Say I have a custom container view controller (MainViewController) where I do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
HomeViewController *homeVC = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
[self addChildViewController:homeVC];
[self.view addSubview:homeVC.view];
}
The HomeViewController will have a button, such as "go", that when pressed will need to advance to the next view controller. So I need to notify the MainViewController of this action. What is the best way to do this?
I'm using a custom container because I need to do custom transitions between the view controllers. When "go" is pressed, some of the views on the HomeViewController will animate while the views from the new view controller are animating into place.
Obviously I could give the HomeViewController a property of type MainViewController and make calls that way, but I'm hoping that there is a cleaner way with the container view controller API.
You can either use delegate or block;
Using delegate
Create a protocol :
#protocol SomeProtocol <NSObject>
- (void)someAction;
#end
Just declare a delegate in HomeViewController.h like this:
id<SomeProtocol> delegate;
and then in MainViewController's viewDidLoad set it like this:
homeVC.delegate = self;
//some where in MainViewController implement the protocol method
-(void)someAction
{
//do something
}
then when you press the button in homeVC, just simply call:
if ([self.delegate respondsToSelector:#selector(someAction)]) {
[self.delegate someAction];
}
Using Block:
In HomeViewController.h declare a block property:
typedef void (^ActionBlock)();
#property (nonatomic, copy) ActionBlock block;
then in MainViewController ViewDidLoad:
homeVC.block = ^(){
//do something
};
then when you press the button in homeVC, just simply call:
self.block();
There's another way too...
Every view controller has a parentViewController property so using that you can do this...
In MainViewController define a method for the action you want to perform...
- (void)someMethod:(BOOL)someParam;
Then in HomeViewController you can do...
MainViewController* parent = (MainViewController*)[self parentViewController];
[parent someMethod:paramValue];
HTH :)
This is a very common pattern. The parent will be the actual instance that will handle the action, by providing a protocol and a default extension.
In Swift 3:
Parent view controller:
protocol SomeProtocol {
func foo()
}
extension ParentViewController: SomeProtocol {
func foo() {
// Parent handles it
}
}
Child view controller:
#IBAction func tapGo(_ sender: Any) {
(parent as? SomeProtocol)?.foo()
}
In my main view controller, I have a button that calls a popover. Since the popover has it's own view controller, its buttons call methods in the popover's view controller. But how would I call a method from the main view controller?
I tried this. In the popover view controller I added a property in the .h
#class ViewController;
#interface PopoverContent : UIViewController <UITextFieldDelegate>
...
#property (strong, nonatomic) ViewController *parentView;
In my popover implementation I did this in viewDidLoad:
self.parentView = [[ViewController alloc] initWithNibName:nil bundle:nil];
In ViewController I have a method called generateHash so I tried
[parentView generateHash];
But I get the error:
No visible #interface for 'ViewController' declares selector 'generateHash'
Any idea what I'm doing wrong? Thanks
remove this line, don't want to create a new instance of view controller
self.parentView = [[ViewController alloc] initWithNibName:nil bundle:nil];
change this line
#property (strong, nonatomic) ViewController *parentView;
to this, so your parent view pointer is of the right class type
#property (weak) ParentView *parentView;
now inside parent views .m file
- (void) createPopup
{
PopoverView *popoverV = [[PopoverView alloc] init];
popoverV.parentView = self;
//And some command to show your popup, addSubview, or presentModal, or whatever
}
Then in PopoverView.m file, you can call methods of the parentView like so
[self.parentView SomeMethod];
This is a good place to use a delegate protocol. In the PopoverContent.h, add something like this:
#protocol PopoverContentDelegate : NSObject
- (void) method1;
#end
Naturally, you can have more than one method, and the method(s) can return values and take parameters like any other method. Also, in the same file, add property called delegate. (Technically, it can be called anything, but everyone who looks at your code will know exactly what you're doing if you call it delegate.)
#interface PopoverContent
#property (weak) id<PopoverContentDelegate > delegate;
//other properties and methods
#end
Finally, in your "main" view controller's .m file, import PopoverContent.h file and set the delegate to self. Also implement method1 to do whatever you need it to do.
//Create the view controller
myPopoverContentController.delegate = self;
//Create the popover with the view controller.
Now, in PopoverContent controller, you can call method1 on the delegate wherever you need to.
[delegate method1];
First, to answer your question, you probably have to define the generateHash method in your ViewController.h file.
Second, I'd suggest that your design approach is not optimal. The generateHash method probably needs to be in another file that can be called from both your ViewController and Popover content controller. For example consider another objective-c .h/.m pair "MyHashMethods":
MyHashMethods.h
+ (void)generateHash;
MyHashMethods.m
+ (void) generateHash
{
// hash code
}
This would allow you to just include MyHashMethods.h in whatever view controllers you need and then call
[MyHashMethods generateHash];
when you need it.