How do I call this -(void){} (function, method? sorry, I forgot the terminology) from another .m file?
I would also like to be able to call it in the local .m file like such [self closeMenu];
Here's the -(void){} :
-(void)closeMenu{
//close the menu
[UIView animateWithDuration:0.6 animations:^{
[UIView setAnimationBeginsFromCurrentState:YES]; // so it doesn't cut randomly, begins from where it is
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[menuView setFrame:CGRectMake(menuView.frame.origin.x, -menuView.frame.size.height, menuView.frame.size.width, menuView.frame.size.height)];
}];
}
You have to declare the method in a .h file that has the interface.
In YourClass.h
#interface YourClass:NSObject
- (void)closeMenu;
#end
In YourClass.m
#implementation YourClass
- (void)closeMenu
{
//Close the menu
}
#end
Then you have to import (#import "YourClass.h") in the other file that you want to call this method from.
#import "YourClass.h"
#implementation OtherClass
- (void)otherMethod
{
YourClass *foo = [[YourClass alloc] init];
[foo closeMenu];
}
#end
Seems like you're talking about some kind of a controller method to collapse some kind of a menuView and looks like this is a global menuView that you would like to share with the rest of your App.
Whenever I have "shared" widgets I use a manager for them.
Can you describe the kind of architecture that you're talking about?
Because the dirtiest kind of "Apple Sample code" approach that pops from my mind is to keep a reference to this baby in the App delegate and from anywhere in your App you could do this:
MyDelegate * delegate= (MyDelegate)[UIApplication sharedApplication] delegate];
[delegate.myCoolMenuController closeMenu];
Hope this works for ya.
Cheers
Related
Hey guys!
I want to change the alpha of a UIButton which sounds actually pretty simple. However, I want to change that alpha from a different class(ViewControllerB.m/.h). I got a class called "ViewController.h/.m" and from this class I call a view which appears on the ViewController like a popup. Now I got a UIButton which displays the popup, when it's touched. If the button was touched its alpha will change to "0.0" and the popup will be shown. I got the code from the popup in another class and I want to change the alpha of the button to "1.0" if the pupup was dismissed. I already got a method, that is called when the popup was dismissed. I tried everything, but it didn't worked so far. Maybe because I'm a beginner at iOS ^^.
I hope you understood what I am trying to say. I will leave the code as it is (clean) to do not confuse you with the ways I tried before.
Here you got the codes of my classes:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
//....
IBOutlet UIButton *myBtn;
//...
}
- (IBAction)OpenPopUp:(id)sender;
Now in my ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
//...viewDidLoad....everything else
- (IBAction)OpenPopUp:(id)sender {
[UIView animateWithDuration: 1.0
animations:^{
myBtn.alpha = 0.0;
}];
}
#end
In my ViewControllerB.h:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface ViewControllerB : UIViewController {
//...some unneccesary outlets
}
//Displaying popup.....
- (void)presentInParentViewController:(UIViewController *)parentViewController;
#end
ViewControllerB.m :
#import "ViewControllerB.h"
#interface ViewControllerB ()
#end
#implementation
//...ViewDidload...and more
- (IBAction)close:(id)sender {
//The close button
[self dismissFromParentViewController];
}
- (void)dismissFromParentViewController {
//Removes the nutrition view from the superview
[self willMoveToParentViewController:nil];
//Removes the view with or without animation
if (!self.shouldAnimateOnDisappear) {
[self.view removeFromSuperview];
[backgroundGradientView removeFromSuperview];
[self removeFromParentViewController];
return;
}
else {
[UIView animateWithDuration:0.4 animations:^ {
CGRect rect = self.view.bounds;
rect.origin.y += rect.size.height;
self.view.frame = rect;
backgroundGradientView.alpha = 0.0f;
}
completion:^(BOOL finished) {
[self.view removeFromSuperview];
[backgroundGradientView removeFromSuperview];
[self removeFromParentViewController];
}];
}
//THE PLACE I WANT TO CHANGE THE ALPHA BACK!
}
I really would appreciate anyones help and if you can please show it me on code examples.
Thank you,
Noah
NOTE: I already looked up this posts but tried unsuccsessfully.
Passing Data between View Controllers
Passing data between view controllers in IOS
Modifying UIButton's alpha property from another class
Change alpha and enabled UIButton of ClassA from ClassB in object c
There are 2 ways of doing it,
In ViewController *viewDidAppear:* method check myBtn alpha. if alpha is zero then set the alpha back to 1.
You can add ViewController as a delegate in ViewControllerB and ViewControllerB notifies ViewController when it is dismissed and then you set the alpha of myBtn back to 1
In my ViewControllerB.h:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#protocol ViewControllerBDelegate <NSObject>
- (void)didHidePopoverController
#end
#interface ViewControllerB : UIViewController {
//...some unneccesary outlets
}
#property(readwrite,weak)id <ViewControllerBDelegate>delegate;
//Displaying popup.....
- (void)presentInParentViewController:(UIViewController *)parentViewController;
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "ViewControllerB.h"
#interface ViewController : UIViewController<ViewControllerBDelegate> {
//....
IBOutlet UIButton *myBtn;
//...
}
- (IBAction)OpenPopUp:(id)sender;
#end
Now in ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
//...viewDidLoad....everything else
- (IBAction)OpenPopUp:(id)sender {
[UIView animateWithDuration: 1.0
animations:^{
myBtn.alpha = 0.0;
}];
}
- (void)didHidePopoverController {
[UIView animateWithDuration: 1.0
animations:^{
myBtn.alpha = 1.0;
}];
}
#end
ViewControllerB.m :
#import "ViewControllerB.h"
#interface ViewControllerB ()
#end
#implementation
//...ViewDidload...and more
- (IBAction)close:(id)sender {
//The close button
[self dismissFromParentViewController];
}
- (void)dismissFromParentViewController {
//Removes the nutrition view from the superview
[self willMoveToParentViewController:nil];
//Removes the view with or without animation
if (!self.shouldAnimateOnDisappear) {
[self.view removeFromSuperview];
[backgroundGradientView removeFromSuperview];
[self removeFromParentViewController];
return;
}
else {
[UIView animateWithDuration:0.4 animations:^ {
CGRect rect = self.view.bounds;
rect.origin.y += rect.size.height;
self.view.frame = rect;
backgroundGradientView.alpha = 0.0f;
}
completion:^(BOOL finished) {
[self.view removeFromSuperview];
[backgroundGradientView removeFromSuperview];
[self removeFromParentViewController];
}];
}
[self.delegate didHidePopoverController];
//THE PLACE I WANT TO CHANGE THE ALPHA BACK!
}
When you are showing the popup just assign ViewController instance as a delegate of ViewControllerB instance
Update: I seached for it and found it. The awser from Anshul Join didn't worked for me but what worked for me was this: Update a label through button from different view
It is much less complicated and easy to implement. There are no delegates. Hope I could help anyone with this.
But summed up: Thanks to Anshul Jain for supporting me and trying to solve this for me. Thank you bro!
I need a view (infoView) to be displayed as an overlay on top of another view. As this infoView should be callable from every view of the app(e.g. introView), I'd like the code to be in the infoViews VC and just call its methods when an action at the currentView (introView) happens. I can't use push and pop, as I need to change the background color (infoView) and especially the alpha of the calling view (introView), so right now I do it with insertSubview.
My Code by now:
introVC .h
- (IBAction) openInf:(id)sender;
IBOutlet InfoVC *infoScreenVC;
introVC .m
- (IBAction) openInf:(id)sender {
[infoScreenVC openInfoMethod];}
infoVC .h
- (IBAction) closeInfoPressed;
- (void) openInfoMethod;
- (void) closeInfoMethod;
infoVC .m
- (IBAction) closeInfoPressed {
[self closeInfoPressed];}
- (void) closeInfoMethod {
[self.view removeFromSuperview];
[self.xx.view setAlpha:1.0f];}
- (void) openInfoMethod {
self.view.backgroundColor = [UIColor clearColor];
[self.xx.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.xx.view];}
When I push the button to show the infoView, my NSLogs tell me the method was called, but I can see the Subview wasn't added. I have absolutely no clue what to insert where right now it says xx in my code, as a VC reference from intro doesn't show me the screen.
If I put that code in introVC an modify it, it does show the infoView, calls the correct method to close, but again can't close (when I'm in introVC). I can't figure out how to tell my app who was the calling VC to get back there.
At some point, when all the code was in introVC I managed to even remove the Subview, but couldn't set the Alpha of introVC back to one.
I do struggle with that since two days.. -.- Or is there maybe an easier solution even?
Thank you very much!
//Edit after sergios answer:
intro.m
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];}
info.h
- (void) openInfoMethod:(introViewController *introVC);
info.m
- (void) openInfoMethod:(introViewController *introVC) { //error occurs here
self.view.backgroundColor = [UIColor clearColor];
[self.introVC.view setAlpha:0.2f];
[((MyAppAppDelegate *)[UIApplication sharedApplication].delegate).window
insertSubview: self.infoScreenVC.view aboveSubview: self.introVC.view];}
and the occurring error says
Expected ')' before 'introVC'
I'm not sure how to pass the VC reference properly.
Thank you for your help!!
//EDIT Working Code:
As it works now, I'd like to sum things up:
- I give the calling VC (introVC) to openInfoMethod on the Action openInf like [infoVC openInfoMethod:introVC].
In openInfoMethod I "save" the calling VC in a local variable of type introVC (?) and add the overlay etc.
When the Action of the infoViewController named closeInfoPressed occurs, it calls infoViewController's method closeInfoMethod like self closeInfoMethod:introVC.
In that method I remove self.view from Superview and set introVC.view's Alpha to 1 like introVC.view setAlpha:1.0f
So the codesnippets are
intro.h
IBOutlet InfoscreenViewController *infoScreenVC;
#property (nonatomic, retain) IBOutlet InfoscreenViewController *infoScreenVC;
- (IBAction) openInf:(id)sender;
intro.m
#synthesize infoScreenVC;
- (IBAction) openInf:(id)sender {
UIViewController *introVC = self;
[infoScreenVC openInfoMethod:introVC];
}
info.h:
- (void) openInfoMethod:(UIViewController *)rootVC;
- (void) closeInfoMethod:(UIViewController *)callingVC;
info.m
- (void) closeInfoMethod:(UIViewController *)callingVC;{
[self.view removeFromSuperview];
[callingVC.view setAlpha:1.0f];
}
- (IBAction) closeInfoPressed{
[self closeInfoMethod:introVC];
[self.view removeFromSuperview];
}
If your problem is "figure out how to tell my app who was the calling VC to get back there", why don't you add a parameter to openInfo selector, like here:
info.h
- (void) openInfoMethod:(introViewController *)introVC;
info.m
- (void) openInfoMethod:(introViewController *)introVC {
<your implementation here>
}
would this work for you?
EDIT: your code from intro.m has got a small problem,
- (IBAction) openInf:(id)sender {
introViewController *introVC;
[infoScreenVC openInfoMethod:];
}
indeed, you are not initializing your introVC variable, so that when you pass it into -openInfoMethod: it will have some weird value and cause a crash.
As far as I can grasp from your code, intro.m should be the implementation file for your introViewController, therefore you can simply call:
[infoScreenVC openInfoMethod:self];
but please, before doing this, confirm that self is actually your introViewController.
This should be ilke this
(void) openInfoMethod:(introViewController *)introvc you are passing parameters in a wrong way.
If I understand your question correctly, your infoView should be a subclass of UIView and instantiated from any of your view controllers using:
InfoView *infoView = [[InfoView alloc] initWithFrame:CGRectMake(originX,originY,width,height)];
Then you simply add it as a subview of your view controllers view:
[self.view addSubView:infoView];
[infoView release]; // It's safe to release it here as your view controller's view is retaining it
And when you are done with it, simply call
[infoView removeFromSuperview];
As an aside, you could create some simple methods inside infoView that include introducing animation when the view is presented or removed. Here's an example for fade in and out which assume you set the alpha to zero initially when you create the view:
- (void)fadeIn {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 1.0f}];
}
And fade out
- (void)fadeOut {
[UIView animateWithDuration:1.0f animations:^{self.alpha = 0f}
completion:^(BOOL finished){self removeFromSuperView}];
}
My main class MMAppViewController has an "IBOutlet UIImageView *padlock". This controller pushes a Level1View view which is my quiz game. The MMAppViewContoller has 2 buttons level 1 and level 2. Level 2 has the padlock on it and will unlock when a certain score is reached. When the MMAppViewController is pushed back, is there a way to hide the padlock. I know the following code will do this but my problem lies in where to put the code:
if(theScore>4){
[padlock setHidden:TRUE];
}
With my Level1View i can put code in the "viewdidload()" section, but it does not work with my main view because it only seems to load once! I tried puting the code in my Level1View class but keep getting errors about tokens or it being undeclared:
[MMAppViewController padlock setHidden:TRUE];
or
[padlock setHidden:TRUE];
Is there a way of either putting this code in my Level1View class, or is there a way of having the code in my MMAppViewContoller class that will work when Level1View is "unpushed"?? (not sure of terminology)
Not knowing more about the structure of your program it's hard to know the right way to achieve this.
There are several possible approaches, but viewDidLoad is only going to be called once and should be used for setting up the view initially, and not for this sort of repeated logic. You probably have a model object somewhere that holds the score. (If you don't, i.e. if theScore is an instance variable on your ViewController, as your snippets might imply, you should move it to it's own model object.) The best way to go about this would be for your ViewController to "observe" the model object that holds the score using Key-Value Observing. Here's how you might achieve that:
Let's say you have the following model object to hold your game session data (here, only the current score):
#interface GameSession : NSObject
#property (readwrite) double score;
#end
... and its corresponding implementation ...
#implementation GameSession
#synthesize score;
#end
And then assuming you have a ViewController declaration that looks something like this:
#class GameSession;
#interface MyViewController : UIViewController
{
GameSession *game;
IBOutlet UIImageView *padlock;
}
#end
You could set up the following methods on the ViewController, such that every time the score value of the model object is modified, the ViewController will automatically update the hidden state of the padlock image view:
- (void)viewDidLoad
{
[super viewDidLoad];
game = [[GameSession alloc] init];
[game addObserver:self forKeyPath:#"score" options:NSKeyValueObservingOptionInitial context: [RootViewController class]];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == [RootViewController class])
{
if ([keyPath isEqualToString: #"score"])
{
NSNumber* newValue = [change objectForKey: NSKeyValueChangeNewKey];
double currentScore = [newValue doubleValue];
[padlock setHidden: (currentScore < 4.)];
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
[game removeObserver:self forKeyPath:#"score"];
[game release];
game = nil;
[super dealloc];
}
For a full explanation of Key-Value Observing, see this web page: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/
Let me know if this isn't clear.
The simple option is to put the code in viewWillAppear:.
Can somebody explain me how exactly does the delegate work in iphone sdk.....???
A simple example how to use the delegate and what are the advantages of using delegate.
Delegate pattern is used widely in iPhone SDK. Consider the examples:
You are running an animation. The underlying system handles the animation for you. But it is natural that you want to do something when the animation is over (say, you want to activate a button or show some text when animation is over). Now how the animation system will know what to do when animation is over? After all this is your custom task. So you will configure a delegate for the animation and the system will call that delegate method when the animation is over. Obviously you will do your custom tasks in this delegate method.
You have a text field and you want to know when the user have tapped or edited something in the field. How you will know that? You will configure a delegate for your text field and predefined delegate method will be called by the UITextField class when that particular field is edited or tapped.
Forget UIApllicationDelegate? The system does the job of loading and running the app. How it will tell you that it's initialization have finished and you can now run your code? It will call applicationDidFinishLaunching method of your app delegate.
You are making an asynchronous http request. After loading the data, your delegate method will be called so that you can now work with the data.
There are many more examples. In order to use delegate, you will require to specify the delegate object and sometimes the selector also. What exactly is needed to be done is dependent on what are you doing. That is, configuring an animation delegate is different from configuring a text field delegate. But the general procedure is same, that is you need to specify your delegate object.
Example code for animation :
CATransition *animation = [CATransition animation];
[animation setDelegate:delegate]; // here delegate is your delegate object
After animation is over, your delegate object's - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag will be called and you will do your customization in this method.
Delegates are a way to decouple message senders and receivers. Rather than a message publisher having to #import the definitions of all the classes that might have an interest in the message, The publisher instead defines a delegate type, and calls a method on that delegate in order to send messages. The receiver class then implements the delegate.
Wikipedia has both an explanation and examples :)
In software engineering, the delegation pattern is a design pattern
in object-oriented programming where
an object, instead of performing one
of its stated tasks, delegates that
task to an associated helper object.
It passes the buck, so to speak
(technically, an Inversion of
Responsibility). The helper object is
called the delegate. The delegation
pattern is one of the fundamental
abstraction patterns that underlie
other software patterns such as
composition (also referred to as
aggregation), mixins and aspects.
Basic definition :
A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program.
more details
scenario (used in message passing) :
Suppose object A calls an object B to perform an action. Once the action is complete, object A should know that B has completed the task and take necessary action. This is how delegation works.
With the help of protocols we can achieve delegation in iOS. Here is the
code :
ViewControllerA.h
#import <UIKit/UIKit.h>
#interface ViewControllerA : UIViewController
{
}
#end
ViewControllerA.m
#import "ViewControllerA.h"
#import "ViewControllerB.h"
#interface ViewControllerA ()<SimpleProtocol>
#end
#implementation ViewControllerA
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSelector:#selector(delegatingWorkToControllerB)withObject:nil afterDelay:3.0];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)delegatingWorkToControllerB{
ViewControllerB *vcB = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewControllerB"];
vcB.delegate = self;
[self presentViewController:vcB animated:YES completion:^{
}];
}
#pragma mark - SimpleProtocol Delegate Method
-(void)updateStatus:(NSString*)status {
NSLog(#"%#",status);
}
#end
ViewControllerB.h
#import <UIKit/UIKit.h>
#protocol SimpleProtocol<NSObject>
-(void)updateStatus:(NSString*)status;
#end
#interface ViewControllerB : UIViewController
{
}
#property(nonatomic, unsafe_unretained)id<SimpleProtocol>delegate;
#end
ViewControllerB.m
#import "ViewControllerB.h"
#interface ViewControllerB ()
#end
#implementation ViewControllerB
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSelector:#selector(informingControllerAAfterCompletingWork) withObject:nil afterDelay:3.0];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}
-(void)informingControllerAAfterCompletingWork{
//you can perform some task here and after completion of the task you can call this to notify the previous controller
[self.delegate updateStatus:#"controller B work has done.. update successfull :)"];
//dismissing the view controller
[self dismissViewControllerAnimated:YES completion:^{
}];
}
#end
Working Example : code
I am working on in-app purchase. In my application we added the following code in appdelegate:
#import "InappPurchaseAppDelegate.h"
#import "MainController.h"
#import "MKStoreManager.h"
#import "MKStoreObserver.h"
#implementation InappPurchaseAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[MKStoreManager sharedManager];
navigationController = [[UINavigationController alloc] init];
[window addSubview:navigationController.view];
MainController *frontController =[[MainController alloc] init];
[navigationController pushViewController:frontController animated:NO ];
[frontController release]; // Override point for customization after application launch
[window makeKeyAndVisible];
}
and added the following code in our controller:
#import "MainController.h"
#import "MKStoreManager.h"
#import "MKStoreObserver.h"
#import "InappPurchaseAppDelegate.h"
#implementation MainController
-(IBAction)InappPurchase:(id)sender
{
[[MKStoreManager sharedManager] buyFeatureA];
}
I also added storekit framework but when the button is clicked nothing happens.
All you need to know is here: http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Overview%20of%20the%20Store%20Kit%20API/OverviewoftheStoreKitAPI.html#//apple_ref/doc/uid/TP40008267-CH100-SW1
It shouldn't take you more than half a day to implement it (maybe a bit more if the content resides on your servers and is not already in the bundle).
The simplest explaination is that your button is not properly configured to send the action message. To test either set a breakpoint for the method or log it like:
-(IBAction)InappPurchase:(id)sender
{
NSLog(#"Buyid method called");
[[MKStoreManager sharedManager] buyFeatureA];
}
If the NSLog or breakpoint are never hit, you need to check the button in Interface Builder and make such it's action is set to the InappPurchase method.
If the InappPurchase method is being called by the button then the problem is in the MKStoreManger object.