ok, this may be a very basic question and I apologise if it is, but its driving me mad and I really need to get a better understanding.
I have an app that I am developing and using a new view controller and xib file for each page.
I call each page by using this code:-
HelpVC = [[[HelpViewController alloc] initWithNibName:#"HelpViewController" bundle: [NSBundle mainBundle]]autorelease];
[self presentModalViewController:HelpVC animated:YES];
Which works great.
However if I have this declared in a file and I then want to call it somewhere else I am getting errors all over the place.
is there any way to initialise all the xib files first in a class file and then call them from that file when needed??
Thanks
This is the error I get back
error: expected specifier-qualifier-list before 'UserInputViewController'
It seems to cause all of my declarations in the .h file to error with the message above.
Some sample code is:-
.h file
#import <UIKit/UIKit.h>
#import "CgePWViewController.h"
#import "LogBackInViewController.h"
#import "LoginViewController.h"
#interface SettingsViewController : UIViewController
{
CgePWViewController *cPWVC;
LogBackInViewController *LBIVC;
LoginViewController *login;
}
#property(nonatomic, retain) CgePWViewController *cPWVC;
#property(nonatomic, retain) LogBackInViewController *LBIVC;
#property(nonatomic, retain) LoginViewController *login;
so basically as soon as I have added in LoginViewController it causes everything else to error, if I take this out then the app runs perfectly.
Does your LoginViewController.h imports the SettingsViewController as well? It seems to be a "cross reference" (I don't know if this term makes sense in English as it does in Portuguese).
Before your
#interface SettingsViewController : UIViewController
put a
#class LoginViewController;
and check if it helps.
Don't initialise your view controllers to put them in properties. Instead, create them as soon as you need them.
Let's assume you want to show a view controller when somebody pushes a button. Add this method to your view controller (let's assume it's named MyFirstViewController):
- (IBAction)someButtonDidPush: (UIButton *)sender {
MySecondViewController *vc = [[MySecondViewController alloc] init];
// Do stuff and then show it. One way may be like this:
[self presentViewController: vc animated: YES completion: nil];
}
Just hook up the button with the method above. No properties needed! You're (probably) done.
Related
I am working on an iOS project and wanted to include a UIView that is reused on multiple screens in the application (appearing at the bottom of different UIViews). I am using a storyboard for the UI work so far but created an .xib file to be used by the reusable view (playerView in code below).
The view gets added but the button I have added to the View is unresponsive, also my background color cannot be changed on the view. I have tried to set background color programmatically and in the .xib with no luck. Very weird symptoms and I tried to instantiate the view from #5 of this article and probably did something wrong. I dont fully understand everything in the article which makes me nervous - for instance my showSubclassedView method returns IBAction but I just call the function name in code and dont use a button (I did hook up the buttons in the view as the article described though).
Here is the code:
EventViewController.m (where I trry and add PlayerView)
#import "EventViewController.h"
#import "PlayerView.h"
#interface EventViewController ()
-(IBAction)showSubclassedView;
#end
#implementation EventViewController
-(IBAction)showSubclassedView
{
[PlayerView presentInViewController:self];
}
PlayerView.h (.h for reusable view)
#import <UIKit/UIKit.h>
#import "Utils.h"
#class PlayerView;
#protocol PlayerViewDelegate
-(void)playerViewTouchedUp:(PlayerView*) playerView;
-(void)playerViewDidDismiss:(PlayerView*) playerView;
#end
#interface PlayerView : UIView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate>*) playerView;
-(IBAction)viewTouchedUp;
-(IBAction)dismiss;
#end
PlayerView.m (.m for reusable view)
#import "PlayerView.h"
#interface PlayerViewOwner : NSObject
#property(nonatomic,weak) IBOutlet PlayerView *playerView;
#end
#implementation PlayerViewOwner
#end
#interface PlayerView ()
#property (nonatomic, weak) UIViewController <PlayerViewDelegate> *delegateViewController;
#end
#implementation PlayerView
+(void)presentInViewController:(UIViewController<PlayerViewDelegate> *)viewController
{
PlayerViewOwner *owner = [PlayerViewOwner new];
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:owner options:nil];
owner.playerView.delegateViewController = viewController;
[viewController.view addSubview:owner.playerView];
}
-(IBAction)viewTouchedUp
{
//forward to delegate
NSLog(#"you clicked a button");
[self.delegateViewController playerViewTouchedUp:self];
}
-(IBAction)dismiss
{
[self removeFromSuperview];
// Forward to delegate
[self.delegateViewController playerViewDidDismiss:self];
}
#end
PlayerView.xib has a UIbutton on it that connects it to viewTouchedUp method in PLayerView.m
Is there anything I did wrong in the code above? Is this the best way to do a reusable view to display on other views?
Thank you!
Here's a workaround I found after not being able to solve this.
New implementation is from this article
I reverted my changes from my initial question and implemented this. It lacks the nice protocol separation for talking back and forth and I might need something like this later but I think now I can still implement a protocol to solve this.
At least with this solution I have usable items in my view and a background that changes!
I want to change the value of a label in my default view controller from a different class.
So I start a simple 'Single View Application' iOS project (Xcode5)
This automatically generates a ViewController for me (which I
understand is the root view controller)
I now add a label in my View and connect it to the ViewController (via IBOutlet mechanism)
I call this outlet 'gameStateLabel', so it looks like this in the ViewController.h file
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
Next, I have a completely separate class which has the logic for my code, and based on a condition in the logic I want to change the UIlabel.
So I try to do this from my other class:
Get an instance of the root view controller like this:
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
I think I now have an instance of the rootviewcontroller in uvc and should be able to reach in and change gameStateLabel.
BUT: I CANNOT do this uvc.gameStateLabel simply does not show up as a property even though it is clearly declared as a property and I've added the #synthesize for it also.
Any help will be greatly appreciated - I've been going nuts over this.
(For ref. I'm used to doing something similar on the Mac side where I'd declare a label as a property of the AppDelegate, get the instance of the Appdelegate and simply refer to the label property and change its text]
Here's the ViewController. Note that gameStateLable is a property
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *gameStateLabel;
#end
#implementation ViewController
#synthesize gameStateLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
And here is my class cls1 (which inherits from NSObject)
#import "cls1.h"
#import "ViewController.h"
#implementation cls1
-(void) dummy{
UIViewController * uvc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
// uvc does NOT show gameStateLabel in intellisense, i.e. uvc.gameStateLabel does NOT work
}
Add #import "mainRootVC.h" in you CustomClass.m file
And create object of mainRootVC such like,
mainRootVC *obj = [[mainRootVC alloc] init];
// Now you can access your label by
obj.gameStateLabel...
Do like this...
YourViewController *rootController =[(YourViewController*)[(YourAppDelegate*)
[[UIApplication sharedApplication]delegate] window] rootViewController];
Try the following too:
ViewController *controller = (ViewController*)self.window.rootViewController;
It will return the initial view controller of the main storyboard.
For sending information from a viewController to other viewController you have:
Delegates:Definiton and examples
NSNotificationCenter: Apple Documentation
NSString *label = #"label text";
[[NSNotificationCenter defaultCenter] postNotificationName:NAVIGATETO object:label userInfo:nil];
You can found tons of examples about those two. I recommend you use one of those.
Hope this helps a bit.
OK. I found two issues.
I had copied the code over from my Mac project and modified it. Something seems to have gone wrong.
I retyped the entire function and it solved most of the problem
uvc should be of the type ViewController* - not UIViewController* as I was doing
Thanks everyone for your replies - much appreciated.
I'm calling a modal viewcontoller from a number of locations and when i close it i'd like to find out what view it is on top of so i can call a update function if it is this custom list i've made.
I'm wondering how i might call a method in the ViewController under the modal view.
Right now i've set up a delegate, but it doesnt seem to call the method that i've set up.
Please see code.
ViewController.h
#interface PICTSharePictViewController : PICTBaseShareViewController <PICTConnModalViewControllerDelegate>
.m
-(void)viewDidLoad{
PICTConnModalViewController *cmodal = [self.storyboard instantiateViewControllerWithIdentifier:#"connModal"];
cmodal.pictDelegate = self;
}
-(void)checkSwitches:(PICTConnModalViewController*)sender{
NSLog(#"-----Check-----");
}
And ModalView
.h
#class PICTConnModalViewController;
#protocol PICTConnModalViewControllerDelegate
-(void)checkSwitches:(PICTConnModalViewController*)sender;
#end
#interface PICTConnModalViewController : PICTBaseViewController {
__weak id <PICTConnModalViewControllerDelegate> sliderDelegate;
}
#property (nonatomic, weak) id <PICTConnModalViewControllerDelegate> pictDelegate;
.m
-(void)viewDidLoad{
[pictDelegate checkSwitches:self];
}
I get no errors or any warnings. Can anyone tell me what I'm doing wrong?
You can access the View Controller that presented the modal View Controller by using the -[UIViewController presentingViewController] method on the modal/presented VC.
I am struggling to make a simple thing (at least I think it's simple) but I just can't do it!
I will try to explain a little bit.
It's an app which displays information. When the user is inside a view, he can click on a button, which displays a popoverview, where he can choose which information he wants to know.
Actually, I can't create an action that changes the UILabel text I created in the main view when the user clicks on the popoverview's buttons.
Anyone has any idea?
Just for you to know: the main view I created a class for it, and also for the popoverview. Although, the popover view I created its design in a XIB file (I don't know if this is important, that's why I am putting this).
Well, I hope you guys were able to understand my question.
Thanks in advance.
Fernando.
Just create a property from the viewcontroller and access it from the consumer (other viewcontroller )
You will have to use delegation in order to see changes in the main view when you are making different actions inside the popover. First, you need to create a protocol inside your popover controller header file:
#import <Foundation/Foundation.h>
#class MyPopoverController;
#protocol MyPopoverDelegate
- (void)valueChanged:(NSString*) newVal;
#end
#interface MyPopoverController: UIPopoverController
#property (weak) id<MyPopoverDelegate> delegate;
#end
Then in .m you implement it like this:
- (void) someActionOccured
{
if([self.delegate respondsToSelector:#selector(valueChanged:)]){
[self.delegate valueChanged:valueYouWantToSendBack];
}
}
Remember that in your main class you have to implement MyPopoverDelegate protocol:
#interface MainViewController: UIViewController <MyPopoverDelegate>
And when you instantiate your popover controller:
/*
** inside MainViewController.m
*/
// remember to assign it's delegate
MyPopoverController *popoverController = [MyPopoverController alloc] init];
popoverController.delegate = self;
Also, you'll have to implement the protocol's method:
/*
** inside MainViewController.m
*/
- (void)valueChanged:(NSString*) newVal
{
// process the string and display it where you need it
}
The Problem
An IBOutlet is released before I have a chance to use it.
What I Want
I want to access a navigation controller from my app delegate so I can reload a table view.
My Setup
I have:
A Main.xib that's set as my main interface in target settings
An IBOutlet to the navigation controller as an ivar on my app delegate
This IBOutlet hooked up to the correct navigation controller in Main.xib
App Delegate is instantiated in the xib but not set as File's Owner
I'm using ARC, Xcode 4.3.2 and iOS5.1
What I've Tried
Changing deployment target
Putting a break point on dealloc for the navigation controller, app delegate - they're never called
Reading everything I can find on ARC and IBOutlets - nothing seems to contradict what I'm doing
Creating a fresh project with just a the minimum classes required - I see exactly the same problem
Code
KPAppDelegate.h
#interface KPAppDelegate : UIResponder <UIApplicationDelegate> {
IBOutlet KPBrowseExpensesNavigationController *nc;
}
#property (strong) IBOutlet KPBrowseExpensesNavigationController *nc;
KPAppDelegate.m
#implementation KPAppDelegate
#synthesize nc;
-(void)setNc:(KPBrowseExpensesNavigationController *)nc_ {
nc = nc_; // This gets called on view load and nc gets set.
}
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[nc viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
UPDATE
I must be doing something really silly here. Even an incredibly simple project still shows this problem. See link below.
Download a simple test project that shows the problem.
In Window nib, set the FilesOwner Class as UIApplication and then point it's delegate from Outlets to the AppDelegate object. This is what is wrong in your project example.
is your outlet from the Interface Builder set as an KPBrowseExpensesNavigationController type?
If not it is not going to create the connection between your nib and ViewController.
You should set its Custom Class as KPBrowseExpensesNavigationController in the Identity Inspector
I am not sure why you declare it as a property & a non-property. I should do something like this:
#interface KPAppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, strong) IBOutlet KPBrowseExpensesNavigationController *nc;
And in your implementation:
#implementation KPAppDelegate
#synthesize nc = _nc; // So you don't accidentally use nc
...snip...
// This is called about 5 seconds after app startup
-(void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects {
// By the time we get here, nc is nil.
UITableViewController *tvc = [[**self.nc** viewControllers] objectAtIndex:0];
[[tvc tableView] reloadData];
}
#end
Hope this helps!
I didn't see where you alloc your nav controller. Just declaring the property won't assign any value to it, so it would be nil. In you -didFinishLaunchingWithOptions in the app delegate, set your alloc/init statement. Everything else looks fine.
KPBrowseExpensesNavigationController *nc = [[KPBrowseExpensesNavigationController alloc] init];
If you have a custom init, you can use that too, but just make sure to set it up before you try and use it.