How to access attributes for a UI element in Interface Builder - objective-c

For example, I have a UISlider that calls - (IBAction)sliderMoved:(id)sender, which performs some task once a new value has been "slid" to through the Value Changed event. But what if I want to do something based on whatever its initial value is?
Hard-coding something to match the default value in Interface Builder would be sloppy and hard to debug later if someone changes the nib file. So, how can I access the default value set for this UISlider in Interface Builder?
AND, more generally speaking, how does one access these attributes for any such UI element? Are there setter/getter methods already synthesized for these?

As Maunil said, Use bindings to connect the UISlider in InterfaceBuilder to a UISlider object in the code. Once this is done, you can access all its methods & properties.
To set the initial value, use the setValue: property of the UISlider, something like:
- (void)viewDidLoad {
...
// where mySlider is declared as a UISlider object and bound to your XIB slider
[mySlider setValue:some_default_value];
...
}
See the UISlider Class Reference documentation for more information.

You can declare the slider in the header file as IBOutlet, and then hook it up in IB. Then you will be able to access all its properties in code.

Related

How to set delegate for subclass

I'm writing own switch class. I'd like to add a delegate to it - examplary if we have UIImagePickerController we add UIImagePickerControllerDelegate to #interface of some viewcontroller and we can set methods like imagePickerControllerDidCancel:(UIImagePickerController *)picker...
I want to do something similar for my class - it's named HSwitch, so I want to add HSwitchDelegate to #interface of some view controller.
I would like to add to this delegate a method valueWasChanged, that I could set in viewController and which would be called each time when slider changes value.
How can I do that? I didn't do it yet, so... please help me :)
Thanks!
If your class is a switch, presumably it inherits from UIControl. If this is the case, don't introduce the complexity of delegates - use target-action instead, and send actions / register targets as you would with any other control. See the UIControl class reference for details. UIControlEventValueChanged would be a suitable event for your needs.

Bind Label to class' property

I'm trying to bind a label (NSTextField) to a class' property. In Interface Builder I bind the label's Value to File's Owner with Model Key Path = self.aString.
File's Owner is a NSViewController's subclass with aString defined as: #property (nonatomic, strong) NSString *aString;
The label is placed inside a View Based NSTableView filled at run-time by a binding with a managed object context.
When i call [self setAString:#"..."] or [self setValue:#"..." forKey:#"aString"] in the class' implementation, nothing changes in the table view. However if the label is placed inside the view it works. Why?
This is a limitation of view-based table views, and from what I know the only way to fix it would be to set TableView.delegate to your File's Owner (or another object if you're trying to bind to that instead).
(I'm hoping for a better answer to explain why, because I don't know why this is the case)
Cake's answer is a good workaround.
I solved by subclassing NSTableCellView and adding to it a NSString property. Then i bound the value of the label to the Table Cell View with the name of the property as key.
You probably don't have direct access to it when it's inside the tableview. Try storing a reference to the tableview and then calling the label. So if your table had a reference named t, connect the label to the table and then:
t.labelName.text = #"string" Although, if it's inside a cell in the table you may need to use cellForRowAtIndexPath and reference the label inside a subclassed cell. If you don't know how to do this I can post some code.

NSControl subclass can't read the target?

The following code:
- (void) setTarget:(id)anObject {
NSLog(#"anObject: %#",anObject);
[super setTarget:anObject];
NSLog(#"Target: %#",[self target]);
}
has this output:
anObject: <DropZoneViewController: 0x15dd5770>
Target: (null)
This is in a subclass of NSControl. So what am I doing wrong?
What I'm trying to achieve: I have an NScontrol that accepts dragging objects. When the dragging ends, I'd like to send the control's action to its target. But how do I get the control's action & target if this above doesn't work?
NSControl doesn’t store it’s own target, that is what it’s cell is supposed to do.
So there are two reasons this might fail:
Your control doesn’t have a cell
In this case you really should create a subclass of NSActionCell to implement your control. Your subclass of NSControl shouldn’t do much besides setting up the cell.
If you don’t want to do it the right way by using a NSCell you’ll have to add instance variables to your NSControl subclass to store the target and action and override the getters and setters to use them.
Your cell is not a subclass of NSActionCell. A regular NSCell doesn’t store a target either.
If you’re using a custom cell that is not a subclass of NSActionCell just change it so that it does inherit from NSActionCell instead of NSCell. If you cannot do this (for example because you’re subclassing a NSCell subclass you cannot change) you’ll have to add the instance variables for target and selector to your cell class and override it’s setters and getters.

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.

Events for custom UIView

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.