So, I want to place a label in my fist view and place in a second one a UISwitch.
But the problem is I can't link together everything.. :/
in my first view i have that
- (void)onRoff {
if (mySwitch1.on) {
test.hidden = YES;
}
else (test.hidden = NO);
}
but here I have an error with mySwitch1 because it's declared in my secondView..
I don't know if it's clear, I want to link a label and a switch in different view..
Thanks !
Indeed you are not very clear. The first thing you might want to try is describe what you did:
how are your two views instantiated?
Let's assume your two views are instantiated from two different nib files.
what is the object you want to have access to your label and switch?
Let's assume it's a view controller. It's a bit unusual for a single view controller to control two views from two different nib files, but after all, why not?
In any case, you can set the owner class for your two nib files to be the class of your view controller. Then in Interface Builder, from the first view, you can bind the label to the file owner's UILabel outlet. And in Interface Builder, from the second view, you can bind the UISwitch to the file owner's second outlet, of type UISwitch.
But perhaps the onRoff methods of yours is actually a method of one of your two view class? The same idea apply: you can set the file owner in the second nib file to be the view class of the first view, and then bind the switch to the file owner's UISwitch outlet.
But it sounds like your design might be worth working on...
Edit: after your comment, here is a bit more...
The problem is that your two view controllers each control a different page and have no reason to know about each other. So you need a middle man object. That could be another controller. Let's use the Application delegate. Then, in the IBAction method of your SwitchViewController, you can do something like:
- (IBAction) switchChangedValue:(UISwitch *) sender {
NSString *newLabelText = sender.isOn ? #"On" : #"Off";
self.labelViewController.label.text = newLabelText;
}
Now how will everybody know about each other? First each view controller will inform the middle man. Here is it for the SwitchViewController:
- (void) viewDidLoad
{
[super viewDidLoad];
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.switchViewController = self;
}
Second, the app delegate will need to coordinate everything:
#interface MyAppDelegate : …
#property (nonatomic, retain) SwitchViewController *switchViewController;
#property (nonatomic, retain) LabelViewController *labelViewController;
#end
#implementation MyAppDelegate
#synthesize switchViewController = _switchViewController;
#synthesize labelViewController = _labelViewController;
- (void) setSwitchViewController:(SwitchViewController *) newSwitchController {
if (newSwitchController != _switchViewController) {
[_switchViewController release];
_switchViewController = [newSwitchController retain];
_switchViewController.labelViewController = _labelViewController;
if (_labelViewController)
_labelViewController.label.text = _switchViewController.switch.isOn ? #"On" : #"Off";
}
}
- (void) setLabelViewController:(LabelViewController *) newLabelController {
if (newLabelController != _labelViewController) {
[_labelViewController release];
_labelViewController = [newLabelController retain];
_labelViewController.switchViewController = _switchViewController;
if (_switchViewController)
_labelViewController.label.text = _switchViewController.switch.isOn ? #"On" : #"Off";
}
}
I left out a number of details, but I hope the big picture is clear.
So you have declared ur UISwitch in the second view and ur label in the first view. All u have to do is just use NSUserDefaults to achieve wat u want. Have the following method in the second view itself. Dont bring it to the first view.
- (void)onRoff {
if (mySwitch1.on) {
[[NSUserDefaults standarduserdefaults]setObject:#"off" forKey:#"state"];
[[NSUserDefaults standarduserdefaults]synchronize];
}
else {
[[NSUserDefaults standarduserdefaults]setObject:#"on" forKey:#"state"];
[[NSUserDefaults standarduserdefaults]synchronize];
}
}
Now in the viewWillAppear method of the first view just chk the value of the NSUserDefaults..
-(void)chkState{
NSString *tempStr=[[NSUserDefaults standarduserdefaults]objectForKey:#"state"];
if([tempStr isEqualTo:#"on"]) {
test.hidden=YES;
}
else {
test.hidden=NO;
}
}
Call this method in the viewWillAppear of the firstview like this....
[self chkState];
Hope this helps....If u want save the state of the switch too then just chk the userdefaults value again in the viewWilAppear method of the 2nd view and based
Related
How can I access the value from an inputField located in a second viewController?
The class name of the second view controller is SettingsViewController and the outlet name for the inputField is setRateInput.
I tried this but it didn't work…
double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];
when I NSLog it comes out as The value is: (null)
Any idea what I'm doing wrong?
Here is the implementation file for the main viewController:
#import "SettingsViewController.h"
#interface ViewController ()
#property (strong, nonatomic) SettingsViewController * settings;
#end
#implementation ViewController
// lazy instantiation
-( SettingsViewController *) settings
{
if (_settings == nil) {
_settings = [[SettingsViewController alloc]init];
}
return _settings;
}
- (IBAction)calculatePrice:(id)sender {
double taxRateFromInput = [[self.settings.setRateInput text]doubleValue];
#end
In theory, you could create a global. Create a new class, call it something like taxRate (.h and .m)
In taxRate.h, add the following code:
#import <Foundation/Foundation.h>
#class MyTaxRate;
#interface TaxRate : NSObject {
}
#property (nonatomic, retain) double * taxRateFromInput;
+(TaxRate*)getInstance;
#end
Then, in your controller, put a "#import taxRate.h" in there. In your .m file, add the following:
#import "TaxRate.h"
#implementation TaxRate
#synthesize taxRateFromInput;
static TaxRate *instance =nil;
+(TaxRate *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [TaxRate new];
}
}
return instance;
}
#end
Note: This is extremely similar in structure to what I'm purposing.
if you have the reference from the object view controller you can just access by the property from your attribute.
You instantiated a new SettingsViewController, but you didn't do anything to instantiate its textfield setRateInput. You can do it when you instantiate it:
_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [UITextField alloc] initWithFrame:someFrame]];
or, as a beter solution, instantiate the text field in -init of SettingsViewController
- init {
if (self = [super init] {
self.setRateInput = [UITextField alloc] initWithFrame:someFrame]];
}
return self;
}
If you use nib files, this would be a lot easier.
Note: setRateInput is a bad name for a property. Consider rateTextField instead.
Edit I forgot to add that you have to add the text field as a subview to its parent view.
So it will be like,
_settings = [[SettingsViewController alloc]init];
_settings.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
[_settings.view addSubView:_settings.setRateInput];
In this case, the setRateInput is retained by its super view. You're not using ARC, so you can call autorelease on your text field.
The better solution: Use - (void) loadView; inside SettingsViewController. Loading the view is the responsibility of the correspondent view controller.
- (void) loadView {
self.setRateInput = [[UITextField alloc] initWithFrame:someFrame] autorelease];
[self.view addSubView:_settings.setRateInput];
}
Edit: xib files and storyboards can help you out. Give these tutorials a try.
You are on the right track, also well done with your lazy instantiation (as
a demonstration that you grasped the concept, I mean).
But note, that outlets don't get connected until viewDidLoad is called. So if you
just alloc/init your viewController (lazily), the outlet to your textfield is pointing to nil.
The outlet doesnt get connected until your controller's view property is accessed, ie the view is displayed.
What you could do is give the settings viewController a handle to your calculating viewController and let it set a public property on the calculating viewController that represents the rate.
This is a common pattern - delegation - where one viewController (settingsViewcontroller) calls a method on its delegate (calculating viewController).
You wouldn't need the settingsViewcontroller property in your calculating viewController then, but just instantiate a new settings viewController every time you want it to be brought up, giving it a reference to your calculating viewController.
Another possibility - maybe even better - is to define a model object that does calculation and takes care of the rate it needs to calculate. Then you could give your settingsViewcontroller a reference to that model object (probably instantiated in your
other viewController), so that it can change the rate on it.
PS: also re think how you instantiate viewControllers generally. The designated initialiser is -initWithNibName:bundle: - so usually, you wouldn't just alloc/ -init them.
If you use storyboards (you probably should!), use storyboard's -instantiateViewControllerWithIdentifier: or use the above mentioned designated initialiser.
I know this should be a simple thing to fix, but I can't see what's going wrong. May be extra pair will help. Here is what I am trying to do.
In my table view controller, there is an (+) button on the navigation controller to add new item.
I have a modal segue that takes it to the next view controller. User fills in a form and hit saves the table view controller reloads with the newly added record.
To do this, I implemented protocol with a delegate.
MyFormViewController.h
protocol MyCustomDelegate <NSObject>
#required
- (void)addNewRecord:(myFormViewController *)formViewController itemToAdd:(Item *)item;
#end
#property (nonatomic,weak) id<MyCustomDelegate> delegate;
MyFormViewController.m
#synthesize delegate;
- (IBAction)addItem:(id)sender {
Item *item = [[Item alloc]init];
item.name = itemName.text;
item.desc = itemDescription.text;
// I am having problem here, self.delegate is being null even though, it's being set in prepareForSegue.
if ([self.delegate respondsToSelector:#selector(addNewRecord:)]) {
[self.delegate addNewRecord:self itemToAdd:item];
}
else{
// delegate is getting set to null for some reason.
NSLog(#"Delegate method not getting called...%#",delegate);
}
}
in MyTableViewController.h
#interface MyTableViewController : UITableViewController
MyTableViewController.m
-(void)addItem:(myFormViewController *)formViewController itemToAdd:(Item *)item{
if(item)
{
MyClass *_itemClass = [[MyClass alloc]initWithPath:#"items/"];
[_itemClass addItemForUser:item];
}
[formViewController dismissViewControllerAnimated:YES completion:nil];
}
in my prepareForSegue method I am setting my tableviewcontroller as delegate.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"addItemSegue"]){
myFormViewController *_showaddTopic = [[myFormViewController alloc]init];
_showaddTopic.delegate = self;
}
After all this, my delegate in myFormViewController is being set to "null". I am not sure why it's not working. It's pretty basic stuff but giving me hard time.
Thank you
myFormViewController *_showaddTopic = [[myFormViewController alloc]init];
_showaddTopic.delegate = self;
There's your problem. You are creating a new MyFormViewController. But that's the wrong MyFormViewController; you want to use the one that is already the segue's destination controller. So you are setting the wrong object's delegate.
(PS Notice my use of a capital letter to start the name of a class? Always do that.)
maybe _showaddTopic.delegate = self; can not written here and shuold this object alloc after at once
I have a question pertaining to why my UITableView won't load a detailView...
I've done it before with an interface builder, but now I'm just trying to do it programatically, purely.
In my tableView.h:
#property (strong, nonatomic) RLCASearchDetailViewControllerViewController *searchDetailViewController;
In my tableView.m:
#synthesize searchDetailViewController = _searchDetailViewController;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.searchDetailViewController)
{
self.searchDetailViewController = [[RLCASearchDetailViewControllerViewController alloc] initWithNibName:#"" bundle:nil];
}
SearchItem *item = [ content objectAtIndex:indexPath.row ];
[self.navigationController pushViewController:self.searchDetailViewController animated:YES];
self.searchDetailViewController.detailItem = item;
}
By the way, I'd tried the initWithNibName: value to be nil, empty string as above, and even #"RLCASearchDetailViewControllerViewController". Nothing works...
in my RLCASearchDetailViewControllerViewController.h:
#interface RLCASearchDetailViewControllerViewController : UIViewController
{
SearchItem *detailItem;
}
#property (strong, nonatomic) id detailItem;
#end
in my RLCASearchDetailViewControllerViewController.m:
#synthesize detailItem = _detailItem;
- (void)setDetailItem:(SearchItem*)newDetailItem
{
NSLog( #"GETS HERE" );
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem)
{
NSLog( #"GETS HERE" );
}
}
- (void)loadView
{
[super loadView];
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
NSLog( #"DOES NOT GET HERE" );
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog( #"DOES NOT GET HERE" );
}
As seen above, when I'd implemented a few debugging prints... It does what it's supposed to in theory but for some reason does not load the views. This manifests itself in the GUI by nothing happening when a table cell is clicked, when the view should change into the subview.
What am I doing wrong? Please help... It's been driving me crazy, and I'd been rummaging through the interweb for a while now in hopes of answers.
Thanks a bunch - I really appreciate it! ;)
Sincerely,
Piotr.
If you aren't using a nib, change this line of code:
self.searchDetailViewController = [[RLCASearchDetailViewControllerViewController alloc] initWithNibName:#"" bundle:nil];
To
self.searchDetailViewController = [[RLCASearchDetailViewControllerViewController alloc] init];
Hope it helps !
Your table view is not embedded in a navigation controller, so it can't push a new view controller.
Since the detail view controller is never displayed on the screen, it never bothers loading its view, which is why you are seeing nothing from your loadView or viewDidLoad methods.
You don't show how you set up the initial view controller for your app, but it should be a navigation controller, with your table view controller as the root view controller.
If you're a beginner, storyboards are much better to use than trying to do it all in code. There are few benefits and lots of drawbacks to avoiding interface builder.
im new to IOS and Objective-C and the whole MVC paradigm and i'm stuck with the following.
I am working on (replica) Contact app, also available in iphone as build in app. i want to pass data through another view controller and the data is pass (null) :(.
My Question is, How do I transfer the data from one view to another?
As most the answers you got, passing data between one controller and another just means to assign a variable from one controller to the other one.
If you have one controller to list your contacts and another one to show a contact details and the flow is starting from the list and going to detail after selecting a contact, you may assign the contact variable (may be an object from the array that is displayed in your list) and assign it to the detail view controller just before showing this one.
- (void)goToDetailViewControllerForContact:(Contact *)c
{
ContactDetailViewController *detailVC = [[[ContactDetailViewController alloc] init] autorelease];
detailVC.contact = c;
[self.navigationController pushViewController:c animated:YES];
//[self presentModalViewController:detailVC animated:YES]; //in case you don't have a navigation controller
}
On the other hand, if you want to insert a new contact from the detail controller to the list controller, I guess the best approach would be to assign the list controller as a delegate to the detail one, so when a contact is added the delegate is notified and act as expected (insert the contact to the array and reload the table view?).
#protocol ContactDelegate <NSObject>
- (void)contactWasCreated:(Contact *)c;
// - (void)contactWasDeleted:(Contact *)c; //may be useful too...
#end
#interface ContactListViewController : UIViewController <ContactDelegate>
#property (nonatomic, retain) NSArray *contacts;
...
#end
#implementation ContactListViewController
#synthesize contacts;
...
- (void)goToDetailViewControllerForContact:(Contact *)c
{
ContactDetailViewController *detailVC = [[[ContactDetailViewController alloc] init] autorelease];
detailVC.contact = c;
detailVC.delegate = self;
[self.navigationController pushViewController:c animated:YES];
//[self presentModalViewController:detailVC animated:YES]; //in case you don't have a navigation controller
}
- (void)contactWasCreated:(Contact *)c
{
self.contacts = [self.contacts arrayByAddingObject:c]; //I'm not sure this is the correct method signature...
[self reloadContacts]; //may be [self.tableView reloadData];
}
...
#end
#interface ContactDetailViewController : UIViewController
#property (nonatomic, assign) id<ContactDelegate> delegate;
...
#end
#implementation ContactDetailViewController
#synthesize delegate; //remember to don't release it on dealloc as it is an assigned property
...
- (void)createContactAction
{
Contact *c = [[[Contact alloc] init] autorelease];
[c configure];
[self.delegate contactWasCreated:c];
}
...
#end
Technically, you shouldn't!
The whole idea is not for "views" to control what happens to the data.
What you want to do is to pass data between controllers (which I imagine is exactly what you are planning to do anyway).
You can have shared model (an instance of an object that both view controllers would access) keeping the data you want to share,
You can use notifications to pass data (it is best suited for certain cases).
You can write something to disk and read it again later.
You can use NSUserDefaults.
You can use KeyChain.
...
The best way is:
declare the appropriate #property in the second view controller
when you create it, simply set the property with
viewController.property = valueYouWantToPass;
I'm a big fan of delegates and protocols.
And in some occasions use a Singleton pattern.
two ways to pass/share data between view controller
create an object and sent the data like this
QGraduteYr *tableverify=[[QGraduteYr alloc]initWithStyle:UITableViewStyleGrouped];
tableverify.mystring=myString
[self.navigationController pushViewController:tableverify animated:YES];
another method is stor it in the delegates and use it via shared delegates
MedicalAppDelegate *appdelegate=(MedicalAppDelegate *)[[UIApplication sharedApplication]delegate];
appdelegate.collnameStr=collStr;
and ust this appdelegates value whereever you need
I've got an array populating a small tableView in a DetailView class, and when the user presses a button I need the array to be sent to another View Controller, to populate a tableView there, but I'm having some difficulty getting it working. This is what I've been trying to do so far:
*DetailViewController.m*
#import "DetailViewController.h"
#import "OtherViewController.h"
-(IBAction) toCart:(id)sender {
OtherViewController *oVC = [[OtherViewController alloc] init];
oVC.shoppingList = sList;
NSLog(#"Ingredients count %d", [sList count]); //This returns a number, so the sList definitely contains values, and the method is definitely being called.
[oVC release];
}
*OtherViewController.m*
#import "OtherViewController.h"
#import "DetailViewController.h"
#synthesize shoppingList;
-(void) viewWillAppear: (BOOL)animated {
NSLog(#"list count: %d", [shoppingList count]); // This returns 0
}
sList is populated elsewhere in the class, and sList and shoppingList are both declared in their respective .h files, with #property (nonatomic, retain)...
Any help much appreciated!
As you are having taBbarcontroller, so you can proceed as follows :
Create references of your you viewControllers(which are associated with tabbar as topViewController) in your appDelegate.
otherViewController = [[tabBarController.viewControllers objectAtIndex:<tabIndex>] topViewController];
make it as #property in appDelegate so that you can access it anywhere in your app.
now,
-(IBAction) toCart:(id)sender {
//appDelegate <--- get reference to your application delegate using [[UIApplication sharedApplicaiton]delegate] do not forget to properly type cast it.
OtherViewController *oVC = [appDelegate otherViewController];
oVC.shoppingList = sList;
NSLog(#"Ingredients count %d", [sList count]);
//This returns a number, so the sList definitely contains values, and the method is definitely being called.
// [oVC release]; no need to release it...
}
//also make sure you do not initialize shoppingList of otherViewController in viewDidLoad(or any other method) of otherViewController, else it will be overwritten(lost its previous reference).
in your appDelegate's .h write
#property OtherViewController *otherViewController;
in appDelegate's.m
#synthesize otherViewController;
in appDelegates's .m (method didFinishLaunchingWithOptions: ) write
otherViewController = [[tabBarController.viewControllers objectAtIndex:<tabIndex>] topViewController];
Thanks
In toCart:, you are creating an OtherViewController and then immediately throwing it away. Whatever OtherViewController is calling -viewWillAppear, it isn't the one you're creating in toCart:. How is that object created and put on the screen? You need a pointer to it to modify it.
Better, though, would be to move your model data out of the view controllers and put it in a single ShoppingCart object. Then all your view controllers would have a reference to it (or you can make ShoppingCart a singleton if that makes sense in your program). This way, any time you change the shopping cart from anywhere, all views will correctly update without having to tell every view controller about every other view controller.