Events for custom UIView - objective-c

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.

Related

Multiple IBOutlets (from different classes) to One Object

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.

Objective C View to Controller Communication

What is the proper way to accept user input in a view and then transfer it to that view's controller? I know the NotificationCenter is one option, but surely there is a more elegant way to transfer data from a view to its controller?
All help is greatly appreciated and I always accept an answer!
Use the delegate protocol design pattern, or target-action by subclassing UIControl. Think about how a UIButton tells a view controller that it's been pressed. In interface builder, you connect an action - a selector something like touchUpInside: to a target - the view controller that owns it. In non-IB, you directly tell the UIButton what selector and what target to use.
Both methods make sense in different cases. For a UITextField, for example, it makes more sense to use delegation because it's possible for the text field to send you any number of events, such as an event when the user begins editing, ends editing, or types a character.
For a button, it makes more sense to use target-action because there's really only one event expressed in different forms.
For swipes and drags and other gestures, use UIGestureRecognizers.
You're looking for Delegation or a Data Source. You can see more information about this here, Delegation and Data Sources
A brief example of this would be, something along the lines of this:
//MyViewSubclass.h
#protocol MyViewSubclassDelegate
//Implement your delegate methods here.
-(void)didTouchView;
#end
#interface MyViewSubclass {
id<MyViewSubclassDelegate>delegate;
}
#property(nonatomic,assign)id<MyViewSubclassDelegate>delegate;
Of course, #synthesize your delegate in MyViewSubclass.m
Now in the class's header, that you want the delegate of MyViewSubclass to be, you need to conform to the `MyViewSubclassDelegate Protocol.
#import "MyViewSubclass.h"
#interface MyViewController : UIViewController <MyViewSubclassDelegate>
In your #implementation of MyViewController., implement the MyViewSubclassDelegate method of -(void)didTouchView.
When you initialize and create your MyViewSubclass object, you set MyViewController as the delegate:
myViewSubclass.delegate = self // Self being MyViewController.
In your MyViewSubclass, when you're ready to forward any information, or simply want to fire a method you would do [self.delegate didTouchView]
Hope this helps !
You are looking for delegation, where the controller set itselfs as the delegate of the view. You know it from UITableViewDelegate.
Make your view a subclass of UIControl and implement the target/action design pattern - use the sendActionsForControlEvents: method to message the controller.
Often the UIKit objects like UITextField have delegate methods that you can implement to perform your business logic. E.g UITextField has a delegate method called - textFieldDidEndEditing: that gets called after the user has dismissed the keyboard.

Creating a new event in Interface Builder

I am developing a new component to be used in Interface Builder, which subclasses UIPickerView to create an interface that is similar to UIDatePicker but also includes seconds. I would like for the developer who uses my component to be able to drag a new Object from the library, configure it to be a TimePickerView class, and use it from there.
That bit works perfectly, but now I would like to implement some of the events that are available in a standard UIDatePicker, specifically the "Value Changed" event. I am not sure how to declare an event in this manner without using a delegate protocol. I am also not sure how to make XCode aware of events that are available on an object. Therefore, I am really asking three questions:
How can I declare an event, such as the Value Changed event on a UIDatePicker?
How can I fire an event from within my TimePickerView?
How can I make XCode aware of this event so that a developer can easily link an event to a controller?
As this doesn't seem to be easy to do, I suspect there could be a reason for this; therefore I would also appreciate comments on my approach and arguments for why I should create a delegate protocol to make this happen.
In Objective C and cocoa framework there's nothing like declaring an event(as you would do for example in C#), the same behavior of an event is achieved using the delegate pattern(this is how all cocoa class handle events), so to implement a custom events with the delegate pattern you can do in this way, for example :
Protocol and Custom class interface declarations :
#protocol myDelegate <NSObject>
-(void)valueChanged:(double) value;
#end
#interface UAKTestDelegate : UIPickerView
#property(weak) id<myDelegate> delegate;
#end
Somewhere in the implementation (fire the event) :
//Example of firing the event ....
if([[self delegate] respondsToSelector:#selector(valueChanged:)]) {
[[self delegate] valueChanged:1.0];
}
So, this first part of the answer should address the first two questions in your post(create and fire custom events), but the response to the third answer is simply you can't ...
Xcode(in this case interface builder) knows about the events that UIControl(or a subclass of it) implements, but there's no way to tell it about your own custom events.
So i think that in your case (if you can) you could subclass directly UIDatePicker and eventually override valueChanged if you need to.

Add my own event to "Sent Events" in Interface Builder menu for my own custom UIView

I have created a subclass of UIView and I would like to have it publish custom events that show up in Interface Builder (actually Xcode4) the same way that controls like UIButton have a bunch of events in the "Sent Events" area when you right click on a control in the Xcode 4 designer. I know I can use Delegation (via Protocols) or Notification (via the UINotificationCenter) to let the objects using my custom view know when certain things happen, but I would like to know if the "The Target-Action Mechanism" (described in the Cocoa Fundamentals Guide) is appropriate/desirable/possible to use and be integrated with the Xcode designer. Coming from a mostly .NET background, this approach seems to be closely related to the .NET event model and makes the most sense to me.
There's UIControlEventApplicationReserved, which gives you a range of event identifiers that your app can use. However, I don't think there's any way to tell Interface Builder about application-defined events, so you won't get the same support for your events in IB as you find for UIControl's standard events. Instead, you'll have to specify the target and action for each app-defined event in code. (Please, someone correct me if I'm mistaken on this point.) That's not at all difficult, but it is a little different.
A simple way to do this is to extend UIControl instead of UIView this will allow you to add a target to all the default events (same as UIButton etc).
Note: in order for my custom UIControl to handle the events as opposed to the controls I layered on top of it I had to ensure that userInteractionEnabled = NO was set on all the layered controls.
You can do this using an IBOutletCollection. The advantage of this approach is that you can link objects in Interface Builder. The downside is that you can't link directly to IBActions (like UIControl). Here is a clean implementation using a protocol:
ObserverProtocol.h
#protocol ObserverProtocol <NSObject>
- (void)observedObjectChanged:(id)sender;
#end
MyObject.h
#interface MyObject : NSObject
{
#private
IBOutletCollection(id<ObserverProtocol>) NSArray *observers;
}
- (void)objectChanged;
MyObject.m
#implementation MyObject
- (void)objectChanged
{
for (id<ObserverProtocol> observer in observers)
{
if ([observer respondsToSelector:#selector(observedObjectChanged:)])
{
[observer observedObjectChanged:self];
}
}
}
#end
Then you just need to implement ObserverProtocol in classes you want to observe the event (and to do the binding in Interface Builder of course).

IBOutlet and IBAction

What is the purpose of using IBOutlets and IBActions in Xcode and Interface Builder?
Does it make any difference if I don't use IBOutlets and IBActions?
Swift:
#IBOutlet weak var textField: UITextField!
#IBAction func buttonPressed(_ sender: Any) { /* ... */ }
Objective-C:
#property (nonatomic, weak) IBOutlet UITextField *textField;
- (IBAction)buttonPressed:(id)sender { /* ... */ }
IBAction and IBOutlet are macros defined to denote variables and methods that can be referred to in Interface Builder.
IBAction resolves to void and IBOutlet resolves to nothing, but they signify to Xcode and Interface builder that these variables and methods can be used in Interface builder to link UI elements to your code.
If you're not going to be using Interface Builder at all, then you don't need them in your code, but if you are going to use it, then you need to specify IBAction for methods that will be used in IB and IBOutlet for objects that will be used in IB.
The traditional way to flag a method so that it will appear in Interface Builder, and you can drag a connection to it, has been to make the method return type IBAction. However, if you make your method void, instead (IBAction is #define'd to be void), and provide an (id) argument, the method is still visible. This provides extra flexibility, al
All 3 of these are visible from Interface Builder:
-(void) someMethod1:(id) sender;
-(IBAction) someMethod2;
-(IBAction) someMethod3:(id) sender;
See Apple's Interface Builder User Guide for details, particularly the section entitled Xcode Integration.
You need to use IBOutlet and IBAction if you are using interface builder (hence the IB prefix) for your GUI components. IBOutlet is needed to associate properties in your application with components in IB, and IBAction is used to allow your methods to be associated with actions in IB.
For example, suppose you define a button and label in IB. To dynamically change the value of the label by pushing the button, you will define an action and property in your app similar to:
UILabel IBOutlet *myLabel;
- (IBAction)pushme:(id)sender;
Then in IB you would connect myLabel with the label and connect the pushme method with the button. You need IBAction and IBOutlet for these connections to exist in IB.
Interface Builder uses them to determine what members and messages can be 'wired' up to the interface controls you are using in your window/view.
IBOutlet and IBAction are purely there as markers that Interface Builder looks for when it parses your code at design time, they don't have any affect on the code generated by the compiler.
Ran into the diagram while looking at key-value coding, thought it might help someone. It helps with understanding of what IBOutlet is.
By looking at the flow, one could see that IBOutlets are only there to match the property name with a control name in the Nib file.
An Outlet is a link from code to UI. If you want to show or hide an UI element, if you want to get the text of a textfield or enable or disable an element (or a hundred other things) you have to define an outlet of that object in the sources and link that outlet through the “interface object” to the UI element. After that you can use the outlet just like any other variable in your coding.
IBAction – a special method triggered by user-interface objects. Interface Builder recognizes them.
#interface Controller
{
IBOutlet id textField; // links to TextField UI object
}
- (IBAction)doAction:(id)sender; // e.g. called when button pushed
For further information please refer Apple Docs
IBAction and IBOutlets are used to hook up your interface made in Interface Builder with your controller. If you wouldn't use Interface Builder and build your interface completely in code, you could make a program without using them. But in reality most of us use Interface Builder, once you want to get some interactivity going in your interface, you will have to use IBActions and IBoutlets.
One of the top comments on this Question specifically asks:
All the answers mention the same type of idea.. but nobody explains why Interface Builder seems to work just the same if you DO NOT include IBAction/IBOutlet in your source. Is there another reason for IBAction and IBOutlet or is it ok to leave them off?
This question is answered well by NSHipster:
IBAction
https://nshipster.com/ibaction-iboutlet-iboutletcollection/#ibaction
As early as 2004 (and perhaps earlier), IBAction was no longer necessary for a method to be noticed by Interface Builder. Any method with the signature -(void){name}:(id)sender would be visible in the outlets pane.
Nevertheless, many developers find it useful to still use the IBAction return type in method declarations to denote that a particular method is connected to by an action. Even projects not using Storyboards / XIBs may choose to employ IBAction to call out target / action methods.
IBOutlet:
https://nshipster.com/ibaction-iboutlet-iboutletcollection/#iboutlet
Unlike IBAction, IBOutlet is still required for hooking up properties in code with objects in a Storyboard or XIB.
An IBOutlet connection is usually established between a view or control and its managing view controller (this is often done in addition to any IBActions that a view controller might be targeted to perform by a responder). However, an IBOutlet can also be used to expose a top-level property, like another controller or a property that could then be accessed by a referencing view controller.
IBOutlet
It is a property.
When the nib(IB) file is loaded, it becomes part of encapsulated data which connects to an instance variable.
Each connection is unarchived and reestablished.
IBAction
Attribute indicates that the method is an action that you can connect to from your storyboard in Interface Builder.
# - Dynamic pattern
IB - Interface Builder
when you use Interface Builder, you can use Connections Inspector to set up the events with event handlers, the event handlers are supposed to be the functions that have the IBAction modifier. A view can be linked with the reference for the same type and with the IBOutlet modifier.
I didn't know you didn't need them anymore, they used to be to make it possible for interface builder to find them in your source, in swift I would image that IBAction is still needed, because it needed to change how your method can be called from interface builder though I imaging #objc would do the same thing. I personal intend to still keep using them because it documents what the method or interface is suppose to do.