I have a UISwith in a viewcontroller A. I want to pass the state of the UISwitch to viewcontroller B. I am using Objective C. This is the code I'm using in viewcontroller A:
if (![switchview isOn]) {
NSLog(#"OFF");
} else {
NSLog(#"ON");
[comment setObject:#"YES" forKey:kESActivityPrivateKey];
}
I need to save the value of the UISwitch in viewcontroller B.
Any help is appreciated.
Don't try to access another view controller's view hierarchy directly. You should treat another view controllers views (and a switch is a kind of view) as private.
Set an IBAction on your switch that points to the owning view controller. In that action save the sate of the switch to a property of your view controller.
You can then access the property from the other view controller.
Related
I have a UITabBarController with Tabs (say Tab1, Tab2, Tab3, Tab4) and UITabBarController is my RootViewController and I'm making an API Call in the same. Since it is a RootViewController I'm displaying Tab1 as my default View. When I get the results to my API Call in UITabBarController. I need to share the details in real time to my Tabs. I have tried few ideas(like NotificationCenter, Singleton Class) but it's not working out. Can somebody help me to fix this? Thanks in advance. If you have a working example I kindly request you to share it with me.
Img Representation:
UITabBarController has a property viewControllers that is an array of view controllers displayed (by index for tab position, but you probably don't need that). One simple solution is when your UITabBarController subclass gets data, it can loop over the viewControllers array and check each for delegate conformance / responds to selector and update accordingly.
That's probably the simplest. Another way would be to have the view controllers in the tabs register for updates. So they conform to a delegate protocol, and get a reference to their tab bar controller (the tab bar controller subclass), and call the tab bar saying "observe updates." The tab bar controller keeps storage of registered observing objects and calls each with new data.
This assumes you are setting the tab's view controllers in IB. If you are doing it programmatically, then with the second option you can just link the tabs to the tab bar controller when you add them. If set in IB you could also do it by overriding -prepareForSegue since embedding the tabs in the root is considered a segue, but you'd still have to cast the destinationViewController as whatever subclass can receive data.
The first option is simple enough and though I don't like casting, it's unavoidable to take advantage that the references you want are right there. Plus, there will in reality only ever be a single-digit number of tabs, so it can't get expensive. Hope this helps.
This is just same like passing the values to another viewController but here you need to use tabBarController's delegate method in below example:
Passing value using delegate method from controller A:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
ControllerB *controllerB = (ControllerB *) [tabBarController.viewControllers objectAtIndex:1];
//In this example, there is only have 2 tab bar controllers (A and B)
//So, index 1 is where controller B resides and index 0 where controller A resides.
self.controllerB.data.text = #"some value!";
//This will change the text of the label in controller B
}
Getting value in controller B
// set property in controller B .h file
#property(strong, nonatomic) UILabel *data;
// in controller B .m file viewDidLoad method
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"getting data: %#",data.text); // getting value
}
How about
-Declare a delegate protocol, say, Tab1ViewControllerDelegate, with a method - (void) tab1ViewController:(Tab1ViewController *) tab1ViewController, didReceiveData: (NSDictionary *) data
make a TabBarController subclass a delegate of your tab1ViewController
when tab1ViewController gets it's data, call [self.delegate tab1ViewController: self, didReceiveData: datDict]
then your TabBarController can distribute the data to its array of viewControllers
I'm trying to make a form that one of the filed takes value from a two level selections' result.
The main progress will something like:
EditViewController ===> CategoryViewController (which embedded inside a NavigationController by storyboard and popped up as a modal view) ===> SubCategoryViewController (Which will be pushed to NavigationController).
Now I have a problem. After user tap to select a value in SubCategoryViewController, I'm supposed to dismiss SubCategoryViewController and return the value to EditViewController. But I don't know exactly how.
Please suggest any solution.
Thank you.
EDIT:
Every one of those view controllers should have a public property for a weak reference to a model object that represents whatever is being edited.
So every ____ViewController.h file would have:
#property (weak, nonatomic) CustomItem *item.
in its interface (assuming a strong reference is somewhere in some data store or array of all the items).
When EditViewController is preparing for the segue to show CategoryViewController modally, it should assign that same reference to CategoryViewController's item property after assigning any data entered in EditViewController's form to item:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//TODO: assign data from controls to item, for example:
//self.item.title = self.titleField.text;
CategoryViewController *vc = (CategoryViewController *)segue.destinationViewController
vc.item = self.item; //pass the data model to the next view controller
}
Likewise for the segue from CategoryViewController to SubCategoryViewController. This ensures that every ViewController is editing the same object in memory. When you dismiss SubCategoryViewController (assuming somewhere in all of this CategoryViewController was already dismissed), viewWillAppear: will be called on EditViewController- there you can refresh any changes made in the modal views to the item property, just like you would when first displaying the view (it's actually the same method that's called):
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.titleField.text = self.item.title;
self.categoryLabel.text = self.item.category;
self.subcategoryLabel.text = self.item.subcategory;
//etc....
}
I have a UIViewController subclass that will itself be subclassed into many custom UIViewControllers. It contains a method to check authentication info, and if the authentication fails, it should segue to a particular view. I am looking at making use of UIStoryboardSegue's *"segueWithIdentifier"* method for this purpose. The question is, what do I specify for the destination parameter, i.e. how do I get the UIViewController instance pertaining to my desired destinationviewcontroller?
I afraid it's not that easy because ever subclass of your view controller could go to different view controller and if you want to do it via segue all of that segue will be different. I think the best solution is let your child view controller decide which segue to fire (which view present/push).
Add your check authentication method like that to the parent view controller
-(void)checkAuthentication
{
if (userAuthenticated)
{
[self userAuthenticatedMethod];
}
else
{
// if you want to go to the same view controller if user not authenticated you can
// perfoem segue like that:
[self performSegueWithIdentifier:#"failedSegue" sender:nil];
// but if it depends on the view controller you are in do it like that
[self userNotAuthenticatedMethod];
}
}
Add declaration of this method to .h file and put empty implementation to .m file:
//in .h
-(void)userAuthenticatedMethod;
//just if you need it
//-(void)userNotAuthenticatedMethod;
//in .m
-(void)userAuthenticatedMethod
{
//override in child
}
//just if you need it
//-(void)userNotAuthenticatedMethod
{
//override in child
}
Now in every child view controller you need to implement userAuthenticatedMethod method and if needed userNotAuthenticatedMethod.
If you want to use segue just do something like that:
-(void)userAuthenticatedMethod
{
[self performSegueWithIdentifier:#"yourSegue" sender:nil];
}
You can also add view controller to view hierarchy programatically. In this scenario each child view controller is responsible to add another view to the view hierarchy.
If you need pass the data you can override prepareForSegue: method in every child VC you want.
I got app with 2 view controllers, I'm typing values via NSStrings in Label and TextField in my first view controller and when I by pushing my navigation button go to my second view controller. When I return to my first view controller, I got entered early values. But when next after that I go to my second view controller - values entered via NSStrings in Label and TextField disappear. How to fix this that the values saved? I tried to use strong and copy properties but that not helps me.
I use segue and storyboards, segue with modal type, I use 1 navigation controller for first view controller. I got code only for modal type. First view controller is root for navigation
UPDATE
User entering values such as NSSting in first and in second VC. On navigation bar of first and in second VC there are bar buttons and with that user go throw VCs
type data in first VC -> go to second -> type data in second VC -> go to first(it saved data) -> go to second(it lost data)
I use that code to return to first VC from second:
[self dismissViewControllerAnimated:YES completion:nil];
Segues always instantiate new controllers, so when you go to the second controller for the second time, you're actually going to a new instance of that controller. If you want to go to the same instance, you can't use a segue. Instead you should make a property in your first controller that points to the second one, instantiate that second one, the first time you go to it, but not on any subsequent presentations (put in an if clause, and if the controller already exists, present it, if not, instantiate it first and then present it). The example below assumes that you have a custom controller of class SecondViewController, and that you've given it the identifier, "Second", in the storyboard.
#property (strong,nonatomic) SecondViewController *secondVC;
-(IBAction)presentSecondController:(UIButton *) sender {
if (! self.secondVC) {
self.secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Second"];
}
[self presentViewController:secondVC animated:YES completion:nil];
}
in my current application, I want to use a certain UICollectionView several times, but with different selection behaviours. Consider the following storyboard layout as "is" (and working):
Tab Bar Controller (2 items):
-> Navigation Controller 1 -> Collection View Controller -> some Table View Controller
-> Navigation Controller 2 -> (Basic) View Controller
The Basic View Controller has two UIButtons which have Storyboard Push-connections to the Collection View Controller. What I want is to transition from the Basic View Controller to the Collection View Controller, but selecting an item from the collection should pop the view and return to the Basic View Controller.
I have set a custom property in the Collection View Controller which gets set in the corresponding prepareForSegue message of the Basic View Controller (or not at all, if the user selects a Tab Bar Item), so there's no problem in detecting which controller or which UI component triggered the push (there are 3 ways: selecting the tab bar item or tapping one of the buttons on Basic View).
The problem is popping the Collection View.
My code so far:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ( self.mode == nil ) {
// do nothing
} else if ( [self.mode isEqualToString:#"foobar"] ) {
// one way I tried
[self dismissViewControllerAnimated:YES completion:nil];
} else if ( [self.mode isEqualToString:#"blah"] ) {
// other method
BasicViewController *targetVC = self.navigationController.viewControllers[ 0 ];
[self.navigationController popToViewController:targetVC animated:YES];
}
}
Unfortunately, my app crashes in the lines dismiss resp. popToViewController. Is it even possible to use the same view controllers in different ways of navigation?
I hope it's enough information to help me out on this one. As you might know, projects grow, and I don't know if there's more code to consider :)
Thanks in advance!
The prepareForSegue: method is not the right place to put that code. It's called right before the segue is performed, which usually means there's allready some kind of transition about to happen.
I'm assuming you've connected your collection view cells with a segue and are now trying to modify the behaviour of that segue depending on the viewcontroller 'before' the collectionVC.
In that case there are some possible solutions:
don't use segues for that specific transition and do any vc-transitions manually
write your own UIStoryboardSegue subclass that can handle the different transitions. See UIStoryboardSegue Class Reference. Then you can set some property of your custom segue in the prepareForSegue: method, to tell the segue which transition it should perform.
use unwinding segues. See What are Unwind segues for and how to use them?
The action of a selected a row in your 'Collection View Controller' differs depending on from where the 'Collection View Controller' was presented. In one case, return to 'Basic View Controller' and in the other segue to 'some Table View Controller'
Implement this by defining tableView:didSelectRowAtIndexPath: with something like:
- (void) tableView: (UITableView *) tableView
didSelectRowAtIndexPath: (NSIndexPath *) indexPath
{
if (self.parentIsBasicViewController) // set in the incoming segue, probably.
[self.presentingviewController dismissViewControllerAnimacted: YES completion: nil]
else
[self performSegueWithIdentifier: #"some Table View Controller" sender: self];
}