How to refer to an object instance created/instantiated in interface builder? - objective-c

When working in interface builder you can layout your interface with different types of objects but I'm unclear as to whether these are instances of objects or some sort of factory method or something like that. Basically if you use Interface builder to layout your objects, especially with subclasses of uiview, how do you refer to a specific instances/objects in your code?

When you place any objects such as UIButton via Interface Builder, these objects are instantiated when a xib file which you place the object is loaded.
You can refer to the object, if you hook it to a instance variable which is defined in a header file via Interface Builder.
But you need to define the instance variable to be displayed in Interface Builder like as follows.
#interface FooObject : NSObject {
UIButton *button;
}
#property (nonatomic, retain) IBOutlet UIButton * button;

You can draw connections between objects in the nib to give those objects references to each other, and you can also draw connections from the file's owner (which will be some pre-existing object from before the nib is loaded, such as a UIViewController). Generally, you'll need to structure your code so that everything that needs to access things in the nib either knows the owning object or is known by the owning object.
On the other hand, there shouldn't be that many outside objects that need to know about the specific elements in your nib or you might have a bit too much coupling.

Related

In what order does setValue:forKey: search for the KVC-compliant method or ivar?

Some background:
I wrote a UIScrollView derived class with an outlet named contentView, similar to the following:
#interface MyScrollView : UIScrollView {
IBOutlet UIView * contentView;
}
...
#end
My outlet, in this case is an iVar, not a property. I made use of my class in Interface builder and connected a view to the contentView outlet. At runtime, however, I discovered that my iVar was still nil and was not set to the desired view object.
Some experimentation revealed that if I renamed the outlet or made my outlet a property instead of an iVar, all would work fine. Further research showed that with my outlet as an iVar named contentView, loading the nib would actually connect my desired view object to a private iVar in UIScrollView named _contentView.
I know that nib loading uses KVC to set values and that the KVC setValue:forKey: method will set a value using any of the following:
set{Key}: method
{key} iVar
_{key} iVar
I suspect, but cannot prove, that an attempt to find the set{Key}: method occurs first, and if that fails, an enumeration of iVars is undertaken to find the {key} or _{key} iVar next. This enumeration probably occurs in an order that processes iVars from superclasses before subclasses.
Is there a documented order in which the above candidates are attempted? In what order are members of superclasses attempted in relation to subclasses?
The specific search algorithm is documented in the Key-Value Coding Programming Guide.

Does adding a NSObject into MainMenu.xib creates a singleton object?

Let say I have a NSObject AppController:NSObject. Using IB, I drag an NSObject control into MainMenu.xib and points the class to AppController. Since MainMenu.xib is loaded once and objects inside MainMenu.xib are in memory for the life of the app, does it make the AppController object a singleton?
Then I can drag an IBOutlet to AppDelegate to access this singleton object. This looks like a quick way. Is this a good practice or to be discouraged?
The standard method I supposed is to add a static AppController *sharedInstance inside the class and use a +(AppController *)sharedAppController for access.
No, it's not a singleton because nothing stops you from creating another instance of the same class in code.
It's just a convenient way to create a single instance.
and objects inside MainMenu.xib are in memory for the life of the app
This is not true. If nobody retains these objects (or holds a strong reference to them under GC), they will get deallocated. This is true. See Peter Hosey's comment below.

How to connect dynamically created objects with Interface Builder object instances in Cocoa?

I use an IBOutlet to refer between objects created in Interface Builder, BUT...
I need to connect an object pointer (or sth) declared in an NSOperation (MyOperation) subclass with my application Controller (with an IBOutlet?) to invoke some methods of AppController. Is there any way to connect (or bind) them ?
What is the best practice to refer to AppController or any other instance created in Interface builder (added as objects) from other objects that are not created on IB too (lets say dynamically created in runtime) ?
The way to do this is to have something that does have an IBOutlet to your object either push pointers to that object into things that are dynamically created, or provide a method for other objects to get that reference.
IBOutlet doesn't make sense in the context of something that is created dynamically, and thus doesn't exist in your nib.

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.

What describes an "Outlet" best in objective-c / Cocoa?

Can someone explain in an humanly understandable way what an "Outlet" is?
It's an instance variable that shows up in Interface Builder, so that you can use IB to plug another object into the outlet.
When you load the nib, the nib-loading system will do the requisite magic to make sure the right object shows up in each outlet.
Edit: I'd intended to write a full blog post around this image (I changed my mind after finishing the image), but even alone, it should help clarify outlets for people. Here you go:
(source: boredzo.org)
From a code point-of-view and IBOutlet is only a hint for Interface Builder. It's actually a macro that compiles to, well, nothing at all. That is, the compiler completely removes when compiling.
But Interface Builder can scan your code for IBOutlet so when you right-click on an object in IB you can see all the outlets that you could connect to other objects.
alt text http://img27.imageshack.us/img27/5512/picture820090228.png
In this example, delegate is a member variable of UIApplication and it is an IBOutlet too.
I just think of it as a pointer to a UI control. Once I made that mental connection in my mind, it made sense.
I would say they are the bridge that connects your user interface objects to the code that uses them. Like the name suggests, they provide a spot to "plug in" your UI to your code.
The IBOutlet keyword is defined like this:
#ifndef IBOutlet
#define IBOutlet
#endif
IBOutlet does absolutely nothing as far as the compiler is concerned. Its sole
purpose is to act as a hint to tell Interface Builder that this is an instance variable that we’re
going to connect to an object in a nib. Any instance variable that you create and want to
connect to an object in a nib file must be preceded by the IBOutlet keyword.
IBOutlet is a symbol that indicates to Interface Builder that an object instance variable delcared as
IBOutlet id ivar_name;
should be presented as an outlet of an instance of the associated class. This allows you to graphically connect objects in Interface Builder such that, after the NIB is loaded (i.e. when the object is sent an -awakeFromNib message), the value of ivar_name will be a pointer to the object you selected as the outlet's value in Interface Builder.
From the Objective-C language standpoint, IBOutlet means nothing.
An outlet is an instance variable in your code (in X-code) that can be assigned a reference to a user interface object (in Interface Builder). You plug the user interface object into the instance variable. The assignment is specified in the NIB file created by Interface Builder.