I have two view controllers and nibs. I populated one view controller with a toggle switch and declared this in its header file:
#public UISwitch *toggleSwitch;
and exposed it as a property like this:
#property (nonatomic,retain) IBOutlet UISwitch *toggleSwitch;
I also connected the switch with toggleSwitch outlet. Then I used this switch in my other view controller like this :
theViewControllerWhereIDeclaredTheSwitch.toggleSwitch.on = YES;
Though everything worked fine with the switch being ON by default but when I switched off the switch it threw an exception: "Thread 1: signal SIGABRT" in the main.m file. I get this error quite often while working with Xcode, this error is a real pain in my ass. Please help.
You should not share UI elements over multiple UIViewControllers.
A better approach would be to share a BOOL or even encapsulate the state in your own object inheriting from NSObject and pass that between the 2 UIViewControllers.
#werner is right.
When programming a Controller and a View associated, you are implementing the NVC Pattern.
The idea is that you have this Controller object that is the brain between a View and a Model that holds datas.
Hence what you should perform in your application is not share the switch state but update a BOOL value in your Model when triggering the switch and share the Model with the two Controllers in order to know the value in the two Controllers.
(CF: wikipedia)
Related
I implemented the following category for UINavigationController inside of one *.m file:
#interface UINavigationController (ConfirmPop) <UINavigationBarDelegate>
#end
#implementation UINavigationController (ConfirmPop)
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
...
return YES;
}
#end
I was trying to check some conditions before popping the current view controller, and it worked all right but I short noticed that that category affected all UINavigationControllers in my app. Why does that happen? I thought this would only happen if I declared it on a header file and if I imported somewhere - which is not the case.
Categories apply globally. There isn't a way to apply them selectively.
Categories are used to add new functionality to all instances of that class, especially when your code isn't responsible for creating instances of that class -- otherwise subclassing might be a better choice.
You could create your own instance of a UINavigationController with the desired behavior and only use it where you want that behavior. Or if that's somehow not possible, you could add property-like methods to the category that toggle the desired behavior on and off.
Just a quick semantic question, but is it considered OK to have multiple IBOutlets, located in different classes, going to one (for example) NSButton in Interface Builder. The reason I ask is I need to enable and disable an NSButton based on events that happen in different classes. Would multiple IBOutlets be OK, or should I be creating a controller class for the Button that would receive a message telling it to change the sate of the button, resulting in only one IBOutlet?
Thanks in advance.
#Wain
The relevant code for the MergeFilesController.h file:
#property (nonatomic, retain) IBOutlet NSButton *mergeFilesButton;
-(void)setMergeFilesButtonState:(BOOL)yn;
Relevant code for MergeFilesController.m file:
- (IBAction)mergeFiles:(id)sender {
//Code goes here
}
- (void)setMergeFilesButtonState:(BOOL)yn {
[mergeFilesButton setHidden:yn];
}
I have another class (called DragDropController) that controls some drag-and-drop functionality for an NSView. From the DragDropController.m file, I want to be able to change the state of the mergeFilesButton based on some stuff that happens from within the DragDropController class.
It is from the DragDropController class that I was trying to call setMergeFilesButtonState.
You should use a controller class. View classes should be used for displaying and hosting controls. Controls should pass interaction details to the controller. The controller should control all of the views.
DragDropController should be generic and not know about the other controller specifically. Instead it should post a notification as it's state changes and other controllers can observe the notifications to determine when updates should be made to the UI.
I have two controllers in the storyboard, embedded in a NavigationController, and there is a segue to switch between these.
Passing data from the first controller to the second one is pretty straightforward by implementing prepareForSegue, and set the properties of the second controller using segue.destinationViewController.
I should pass back data to the from the second controller to the previous one also. I googled, but I have not found any simple, but working code to demonstrate it.
Would you be so kind give me a simple sample about the best way to do it?
Thanks in advance!
In your second view controller class you create a protocol and delegate. The first view controller will set it self as the delegate in prepareForSegue and implement the protocol methods. The second view controller will then call the methods to pass data back to the first view controller. Here is some code from one of my projects as an example.
#protocol TableSelectorDelegate <NSObject>
#optional
- (void)didMakeSelection:(id)selectionString forType:(NSString *)dataTitle;
- (void)didAddNewValue:(NSString *)newValue forType:(NSString *)dataTitle;
#end
#interface TableSelectorViewController : UITableViewController
#property (nonatomic, weak) id<TableSelectorDelegate> delegate;
#end
when you set the data you're passing to the second controller you can also set a pointer to the previous one.
The "recommended" way of doing this is using a delegate. Have the first view controller set itself as the delegate of the new view controller during the -prepareForSegue: call, then when you're done, you call whatever delegate methods you've defined.
This is a bit more work than tightly coupling the two controllers, but it actually saves time if you ever find you need to use the controller in a slightly different way. If you watch the WWDC'11 video on using IB and Storyboards, they actually go through this pattern in depth and include code examples and demos, so I recommend taking a look at that.
I've been studying all of the variants to this question of how to pass data from one view controller to another and have come to see that Apple's Second iOS App Tutorial has not only the code but a lovely explanation of everything involved.
one of my view controllers has several UISwitches, and I want another view Controller to be able to access the values of the UISwitches for If/and statements. How do I do this in Objective-c?
This is a bad idea as it would create an unneeded dependency between the view controllers.
If you still want to do it, just pass a reference of the first view controller with the switches to the second view controller. Then, in your second view controller just access the corresponding UISwitch's on property.
However, instead of going that route, I strongly suggest that you create a custom class to hold the boolean state of each UISwitch. An instance of this class could either be a singleton, or contained in the application delegate. See this answer for how to do it with both approaches.
A custom class is better because a UISwitch is just a way to represent some property in your data model. And if tomorrow you replaced the UISwitch with another fancy
control, the second view controller should still continue to work. Both view controllers have a reference to an object of this custom class. Whenever there is a change, the first controller updates this object.
The class interface could be something like this:
#interface DataValues : NSObject {
BOOL first;
BOOL second;
BOOL third;
}
#property BOOL first;
#property BOOL second;
#property BOOL third;
You probably don't want to do that. If you want a second ViewController to have different behavior based on switches thrown in the first, you should just bind the switches to User Defaults, which you can read anywhere in your app.
http://icodeblog.com/2008/10/03/iphone-programming-tutorial-savingretrieving-data-using-nsuserdefaults/
What's the best way for registering events for my UIView subclass, so that I can connect them to IBAction-s in interface builder?
Currently I've just got a standard UIView dropped onto my main view and I've set the class to "RadioDial" (my custom class). This displays the view fine, but I have no idea how to get events out of it.
Thanks
Please clarify: do you mean that you would like Interface Builder to offer your view controllers to wire up custom events that your view subclass will be emitting (much like the Button controls allow you to wire up Touch Inside, etc)?
If you need this type of functionality, you will need to use a generalized 'delegate' property on your View combined with a protocol.
#protocol RadioDialDelegate
-(void)dialValueChanged:(id)sender
#end
#interface RadioDial
{
id<RadioDialDelegate> radioDelegate;
}
#property (nonatomic, assign) IBOutlet id<RadioDialDelegate> radioDelegate;
This will allow the controller to wire up to the view (assuming it implements RadioDialDelegate) and receive any events that come out of the view. Alternatively, you can use an untyped delegate and in your View code, use a late bound call:
if([radioDelegate respondsToSelector:#selector(dialValueChanged:)]) {
[radioDelegate dialValueChanged:self];
}
Create a method in your view controller (if nothing else, you should have a RootViewController in you project). Let's say your method is
-(void) buttonClicked { code code code }
In the controller's header file (for example RootViewController.h) you then put:
-(IBAction) buttonClicked;
And in IB you right-click your button/radio dial/whatever. You will see a list of events and you can drag FROM the connector of the event you want your controller to receive, to the object in IB that represents the controler (probably First Responder). This depends on how your IB structure is set up, but it should be straightforward.
Another alternative is to learn how to create UIViews programatically, and forget about IB for the time being. Opinions are divided about whether it's better to learn to use IB at the outset, or whether it's better to learn how to do everything in code and save IB for later. In any case, it's necessary to learn both ways of setting up an interface at some point.