📜 ⬆️ ⬇️

Familiarity with Interface Builder. Connections between objects.

Crosspost from the blog " Programming in Python and
Objective-C for Mac OS and for iPhone / iPod Touch "
Dedicated to comments # 1 , # 2 and # 3 (oh, hell, do not read the last hellraiser09 )


The process of creating any application can be divided into three stages: the creation of an interface, the direct writing of code and debugging. In the first part of my articles, I want to introduce you to Interface Builder (hereinafter simply IB), a tool for visual creation and testing of interfaces, included in the Mac OS developer SDK, using the example of developing an interface for the iPhone. The way to create a program interface for Mac OS X is not much different from the principles below, so this guide can be used to develop interfaces for a “big” Mac OS with some differences that I’ll mention when the time comes.


')
Creating an interface using Interface Builder typically includes:



I propose to go through these points and give an explanation of particularly difficult places. I’ll warn you in advance that I will not go into details and decipher banal assignments of properties to interface elements, which any novice programmer doesn’t understand, and focus on the problematic and difficult to understand concepts that I encountered during my introduction to the program. and I am sure that the same questions could arise for you if you have already tried to understand the examples of applications for the iPhone available on the website developer.apple.com.

The composition of the windows in Interface Builder



I propose to begin our acquaintance with IB from the opening of the program interface from the project with which we met in one of the past posts . For those who didn’t have a chance to read my previous articles, simply create a new project called “Empty” for iPhone based on the Window-Based Application template, and open the xib interface file that comes with it (xib and nib are the same). Then use the keyboard shortcut Shift + Command + I property inspector, which I will refer to in the storytelling process.



The Library window (component and resource libraries) is divided into two parts: the Objects component library (navigation line, text field, input fields, buttons, etc.) and Media resources (images, sounds, etc.).

The Property Manager panel allows you to set object attributes, view and configure connections between objects.

The nib file window contains the top-level objects of your application. I want to draw your attention to this window and give explanations to each of the objects.



File's Owner and First Responder are so-called proxy objects - these are “storages” for objects that are used in the program interface, but they are not included in the nib file. The proxy objects are not initialized when loading a nib file in the program body; instead, they are replaced with real objects in the running application. Such replacements occur automatically, but you can manually specify the objects to be replaced when the interface file is loaded into the program. Simply put, proxy objects are just links.

In our application, File's Owner means an object that loads a nib file into a program. In our case, this is UIApplication, which delegates the authority to manage the program to our class EmptyAppDelegate. When in the future you will create additional interfaces, and there may be several of them in the program and they may be loaded into the application at different times depending on the need, you will see that File's Owner will be a reference to an object of the NSObject class. This is done on purpose, since in the case of loading a nib file in an application, an object of any class can be responsible for it, but all classes have one ancestor - NSObject.

The object First Responder in the process of the application is constantly changing. Cocoa uses several factors to determine which object should play the role of First Responder at the moment: which window is now active, which view has received focus, and so on. Typical actions for which First Responder is responsible in the program: work with the clipboard, manipulate text, document-level operations (undo, redo, save), user-defined actions, etc. Now its purpose is not entirely clear, but as it is used in my examples, I will tell the details of its application and everything will fall into place.

EmptyAppDelegate is a class to which UIApplication has delegated authority, i.e. File's Owner in our case (for more information about this procedure, you can read in the post " Studying the emptiness ").

Window is an object representing the main window of our application. Your application should not have more than one window - an instance of the UIWindow class. In situations where you need to change the interface, use the View view instead of the window change. I will tell about it below.

Switch the viewing of the window of the nib-file in the list mode - this form will facilitate the further configuration of the application interface.



Creating links between objects



Probably one of the first difficulties faced by the developer in IB is the communication between the objects. The new concept of customization of methods and properties, based on the specifics of the Objective-C language to communicate by sending messages, causes misunderstanding, although the meaning of the work is quite simple. In the process of creating relationships between objects, two terms are used: Outlet and Action.

Outlet is a regular object variable that refers to an object in the application interface.

Our interface already contains some examples of Outlets. In the nib file window, select the File's Owner object and switch to the Connections tab in the property inspector. For the File's Owner object, the delegate variable is defined, which refers to the delegate object of the UIApplication class, in our case the Empty App Delegate is the main class of our application.



Select the latter and see its properties. It, in turn, also has one variable - the window, which contains a reference to the UIWindow object or, more simply, to the main window of our application.



The Referencing Outlets subsection is a list of variables that refer to our object to other objects.

In the application code, such class variables differ from the usual type specifier - IBOutlet. Open the EmptyAppDelegate.h file in Xcode.

 #import <UIKit / UIKit.h>

 @class EmptyViewController;

 @interface EmptyAppDelegate: NSObject <UIApplicationDelegate> {
     IBOutlet UIWindow * window;
 }

 @property (nonatomic, retain) UIWindow * window;

 @end



The IBOutlet specifier of the window variable and any other variables means that the assignment of a new value to such a variable affects the interface of our program: it changes the value of an element, its availability, color, font, and many other properties. The meaning of this phrase will become much clearer after considering the example.

An Action type link in Interface Builder is required to transfer messages from one object to another. Whenever the user interacts with the program interface: presses buttons, moves the slider, enters text into the input field, messages are generated that can be processed in their code.

In the Library window, go to the Objects tab and drag a UIView element onto our form. Its size will automatically change to cover all free space in the window. This is normal.



Here I want to make a small digression. As you remember, I said in one of my past posts that an object of type UIWindow is a child of UIView. In our form there is already an object of type UIWindow, which defines the main window of the application, and I could implement all the examples below taking it as the basis for the layout of the interface elements. But from the point of view of programming an application for the iPhone, it is more correct to use the UIView object as the area of ​​the program interface. Usually, in an iPhone application, not even one is used, but many Views that change during the operation of the application to present various data. Recall, for example, the Settings program on your iPhone / iPod Touch. Changing windows when selecting the settings section (mail, music, main) is implemented just due to numerous View in the application, and the UIViewController class object is responsible for the View change process, but I will tell about it in the next article. In addition, I would like to tell you about one of the advantages of Interface Builder, which cannot be demonstrated without implementing a new class in IB.

Let's return to our form. Select the View object on our form by clicking on an empty space in the window and go to the Identity tab of the property inspector. In the Class Outlets section, add a new variable named label and type UILabel, and in the Class Identity section, give a name to our new class reView.



Drag a Label element from the Library to the center of our form. Resize it so that the element takes up the entire width of the window, and align the text to the center.



Now we need to establish a connection between this variable and the Label object on our form. There are three ways:

  1. With the Ctrl key pressed, click on the View object in the application window and without releasing the mouse button, drag the line that appears to the Label object on the form.



    After that, release the button and select the label variable from the drop-down list of possible options for variables declared in the UIView class.



  2. Select the Label object on our form and go to the Connections tab in the property inspector. Left-click on the circle opposite New Referencing Outlets and draw the appeared line to the View object on the form. After releasing the mouse button, select from the list of label variables that appears.



  3. Right-click (or Ctrl + click) on View in the nib file window. In the class links window that appears, click on the circle opposite the label variable and connect its line with the Label object on the form.





Drag a Round Rect Button from the library of elements onto our form and name the “Remind” button.



Then select the View object, go to the Identity tab and in the Class actions section add a new element called touchIt. And then using any of the above methods, tie it with a button on the form. In the drop-down list, select the Touch Up Inside method.



Now when you click on the button, a message will be sent to the View object. Or rather, at the moment when the button is pressed (Touch Up Inside is called when the button is released), the touchIt method of the reView class will be called.

When creating Action and Outlet relationships, one-to-many connections are allowed. That is, we could add a few more elements to our form and associate them with the click of a button. In this case, the call to Touch Up Inside led to the reaction of several elements at once. Or in the case of many links with the Label element on the form, we could change its value from different classes in the course of the program.

Note also that the type of connection depends on the type of connection (Outlet or Action): from button to view - action, when pressing the button calls the method in view; from view to label - outlet, when changing a variable inside a class implementation causes changes in an object on a form.

Finally, select the Label object in the application window and clear its value.

As you can see, the process of creating actions in our application is not much different from creating outlets. Let's now take a look at the code that performs the action.

Interface Builder provides a number of amenities in terms of creating new classes that will give less attention to code and reduce development time. As you have noticed, we created a new class derived from UIView in Interface Builder, but we lack the files that implement it. To do this, IB has a powerful function that facilitates our work. Select the View object in the nib file window, then go to the File menu and call the Write Class Files command.



Leave the default class name reView and click save. In the new window, check the box that adds the files of the new class to our project in Xcode.



Switch to Xcode and see if the miracle happens. Files reView.h and reView.m are added to our project. Drag them from the project root to the Classes folder for subordination.



Open the file reView.h

 #import <UIKit / UIKit.h>
 #import <Foundation / Foundation.h>

 @interface reView: / * Specify a superclass (eg: NSObject or NSView) * / {
     IBOutlet UILabel * label;
 }
 - (IBAction) touchIt;
 @end



Wow, isn't it? All that remains is to describe the label property and specify the parent class:

 #import <UIKit / UIKit.h>
 #import <Foundation / Foundation.h>

 @interface reView: UIView {
     IBOutlet UILabel * label;
 }

 @property (nonatomic, retain) UILabel * label;

 - (IBAction) touchIt;
 @end



Switch to the class implementation; describe the implementation of the touchIt method:

 #import "reView.h"

 @implementation reView

 @synthesize label;

 - (IBAction) touchIt {
     label.text = @ "Call your parents!";
     label.textColor = [UIColor redColor];
 }
 @end



Let me take another digression here. When I first encountered the program on Objective-C, I could not understand why putting some identifier @ in front of all string expressions. When I found the answer, I realized that I can not share it with you. The @ "" directive hides the creation of a new object of the NSConstantString class so that the programmer does not waste time on his declaration each time he works with strings.

For those who read my post " Introduction to Objective-C " I will give a deeper explanation of the work of this directive. The documentation nowhere describes this class, but it is known that you do not need to worry about releasing the string objects of this class after use. I suppose that initialization takes place as follows:

 [[[NSConstantString alloc] initWithSomething: "Our String"] autorelease]



I think you already guessed how this code works. A new object of the NSConstantString class is initialized and the delayed release of an object from memory is immediately done by calling the autorelease method. As you remember, the object in this case will be released later: after the end of the section of code where this method was called.

An NSConstantString object can be passed as a parameter to a function or as a value into a variable where the retain (in general) its value will be produced, which will increase the number of references to an object by 1. And this means that by the time the release is called in AutoReleasePool, the number of references to the object will be 2, and we will save the object until we finish working with it.

In the implementation of the touchIt method, we used another new class for us, UIColor. It returns an object describing the color specified during initialization. The UIColor object is initialized using the method of the redColor class, therefore, it does not require calling the alloc method, or releasing the object after use.

Save all changes and run our application.



In the middle of our form there is a “Remind” button, clicking on which leads to the appearance of a red inscription “Call your parents!”.

Interface Builder works closely with Xcode. Therefore, when you declare a new variable or method with an IBOutlet or IBAction type specifier in the header file, they are immediately available in the IB Linking window. To see how this happens, change the class declaration reView, in accordance with the example:

 #import <UIKit / UIKit.h>
 #import <Foundation / Foundation.h>

 @interface reView: UIView {
     IBOutlet UILabel * label;
     IBOutlet UITextField * textField;
 }

 @property (nonatomic, retain) UILabel * label;
 @property (nonatomic, retain) UITextField * textField;

 - (IBAction) touchIt;
 @end



Switch to the IB window and call the links window of the reView object. Now we can create a new connection between our textField variable and an object on the form. But note that this must be an element of type UITextField. After creating the connection, you can play around with the properties of the element in the program code and see how it will look in the form after the application starts. I advise you to practice with as many interface elements as possible for a better understanding, and we will delve into more complex examples in the following articles.

This review was prepared on Mac mini G4 with Mac OS X 10.5.4 installed and iPhone SDK (build 9M2199a). How I managed to run the iPhone SDK on the PowerPC platform, I will tell in the next post very soon.

Download project archive (14Kb)


Epilogue



In the end I want to say thank-you words:
  1. the creator of this blog is hellraiser09 , who became a pioneer in this topic on Habrahabr. It is a pity that he abandoned his blog to develop, but I will try to replace it with as much as I have enough.
  2. I want to say many thanks to the people who made the blog engine Byteflow for their work and help in setting up a blog


It has long been itching to print a few wishes to bloggers. I understand that Habr is a great place to promote your blog (in fact, I myself am doing this now). But please, before doing the promotion, pay attention to its content. Try blogging for a month. If you get bored - do not waste time harabrachiteli. How many times having seen the word “crosspost” I clicked on the link and, going to the author’s site, I left it with disappointment almost immediately. Do you know why? Because there is empty or stupidly nothing to read!

If you nevertheless decided to make an advertisement on Habré, then fill the blog with interesting articles so that the first visitors would have something to read, besides the acquaintance post and I will write in this blog about a brain biopsy. If you want to be interested in reading, do not try to write often, but write meaningfully so that even your old posts can be useful to look through again. Deliver unique information and do not write banal things, stupid things and short posts that do not carry meaning.

Thank you all for your attention.

Source: https://habr.com/ru/post/30553/


All Articles