Home > Articles > Programming > C/C++

Objective-C Boot Camp

  • Print
  • + Share This
This chapter is from the book

Methods, Messages, and Selectors

In standard C, you’d perform two function calls to allocate and initialize data. Here is how that might look, in contrast to Objective-C’s [[Car alloc] init] statement:

Car *myCar = malloc(sizeof(Car));
init(myCar);

Objective-C doesn’t use function_name(arguments) syntax. Instead, you send messages to objects using square brackets. Messages tell the object to perform a method. It is the object’s responsibility to implement that method and produce a result. The first item within the brackets is the receiver of the message; the second item is a method name, and possibly some arguments to that method that together define the message you want sent. In C, you might write

printCarInfo(myCar);

but in Objective-C, you say

[myCar printCarInfo];

Despite the difference in syntax, methods are basically functions that operate on objects. They are typed using the same types available in standard C. Unlike function calls, Objective-C places limits on who can implement and call methods. Methods belong to classes. And the class interface defines which of these are declared to the outside world.

Dynamic Typing

Objective-C uses dynamic typing in addition to static typing. Static typing restricts a variable declaration to a specific class at compile time. With dynamic typing, the runtime system, not the compiler, takes responsibility for asking objects what methods they can perform and what class they belong to. That means you can choose what messages to send and which objects to send them to as the program runs. This is a powerful feature—one that is normally identified with interpreted systems such as Lisp. You can choose an object, programmatically build a message, and send the message to the object—all without knowing which object will be picked and what message will be sent at compile time.

With power, of course, comes responsibility. You can only send messages to objects that actually implement the method described by that selector (unless that class can handle messages that don’t have implementations by implementing Objective-C invocation forwarding, which is discussed at the end of this chapter). Sending printCarInfo to an array object, for example, causes a runtime error and crashes the program. Arrays do not define that method. Only objects that implement a given method can respond to the message properly and execute the code that was requested.

2009-05-08 09:04:31.978 HelloWorld[419:20b] *** -[NSCFArray printCarInfo]:
unrecognized selector sent to instance 0xd14e80
2009-05-08 09:04:31.980 HelloWorld[419:20b] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '*** -[NSCFArray
printCarInfo]: unrecognized selector sent to instance 0xd14e80'

During compilation, Objective-C performs object message checks using static typing. The array definition in Figure 3-1 is declared statically, telling the compiler that the object in question is of type (NSArray *). When the compiler finds objects that may not be able to respond to the requested methods, it issues warnings.

Figure 3-1

Figure 3-1. Xcode’s Objective-C issues warnings when it finds a method that does not appear to be implemented by the receiver.

These warnings do not make the compilation fail, and it’s possible that this code could run without error if NSArray implemented printCarInfo and did not declare that implementation in its published interface. Since NSArray does not, in fact, implement this method, running this code produces the actual runtime crash shown previously.

Objective-C’s dynamic typing means you can point to the same kind of object in several different ways. Although array was declared as a statically typed (NSArray *) object, that object uses the same internal object data structures as an object declared as id. The id type can point to any object, regardless of class, and is equivalent to (NSObject *). This following assignment is valid and does not generate any warnings at compile time:

NSArray *array = [NSArray array];
// This assignment is valid
id untypedVariable = array;

To further demonstrate, consider a mutable array. The NSMutableArray class is a subclass of NSArray. The mutable version offers arrays that you can change and edit. Creating and typing a mutable array but assigning it to an array pointer compiles without error. Although anotherArray is statically typed as NSArray, creating it in this way produces an object at runtime that contains all the instance variables and behaviors of the mutable array class.

NSArray *anotherArray = [NSMutableArray array];
// This mutable-only method call is valid but
// produces a compile-time warning
[anotherArray addObject:@"Hello World"];

What produces a warning here is not the creation and assignment. It’s the use. Sending addObject: to anotherArray uses our knowledge that the array is, in fact, mutable despite the fact that it is statically typed as (NSArray *). That’s something the compiler does not understand. This use generates a compile-time warning, namely:

'NSArray' may not respond to '-addObject:'

At runtime, however, the code works without error.

While assigning a child class object to a pointer of a parent class generally works at runtime, it’s far more dangerous to go the other way. A mutable array is a kind of array. It can receive all the messages that arrays do. Not every array, on the other hand, is mutable. Sending the addObject: message to a regular array is lethal. Doing so bombs at runtime, as arrays do not implement that method.

NSArray *standardArray = [NSArray array];
NSMutableArray *mutableArray;
// This line produces a warning
mutableArray = standardArray;
// This will bomb at run-time
[mutableArray addObject:@"Hello World"];

The code seen here produces just one warning, at the line where the standard array object is assigned to the mutable array pointer, namely “assignment from distinct Objective-C type.” Parent-to-child assignments do not generate this warning. Child-to-parent assignments do. So do assignments between completely unrelated classes. Do not ignore this warning; fix your code. Otherwise, you’re setting yourself up for a runtime crash. Because Objective-C is a compiled language that uses dynamic typing, it does not perform many of the runtime checks that interpreted object-oriented languages do.

Inheriting Methods

As with data, objects inherit method implementations as well as instance variables. A Car is a kind of NSObject, so it can respond to all the messages that an NSObject responds to. That’s why myCar can be allocated and initialized with alloc and init. These methods are defined by NSObject. Therefore, they can be used to create and initialize any instance of Car, which is derived from the NSObject class.

Similarly, NSMutableArray instances are a kind of NSArray. All array methods can be used by mutable arrays, their child class. You can count the items in the array, pull an object out by its index number, and so forth.

A child class may override a parent’s method implementation, but it can’t negate that the method exists. Child classes always inherit the full behavior and state package of their parents.

Declaring Methods

As Listing 3-1 showed, a class interface defines the instance variables and methods that a new class adds to its parent class. This interface is normally placed into a header file, which is named with an .h extension. The interface from Listing 3-1 declared three methods, namely:

- (void) setMake:(NSString *) aMake andModel:(NSString *) aModel
    andYear: (int) aYear;
- (void) printCarInfo;
- (int) year;

These three methods, respectively, return void, void, and int. Notice the dash that starts the method declaration. It indicates that the methods are implemented by object instances. For example, you call [myCar year] and not [Car year]. The latter sends a message to the Car class rather than an actual car object. A discussion about class methods (indicated by “+” rather than “-”) follows later in this section.

As mentioned earlier, methods calls can be complex. The following invocation sends a method request with three parameters. The parameters are interspersed inside the method invocation. The name for the method (that is, its selector) is setMake:andModel:andYear:. The three colons indicate where parameters should be inserted. The types for each parameter are specified in the interface after the colons, namely (NSString *), (NSString *), and (int). As this method returns void, the results are not assigned to a variable.

[myCar setMake:@"Ford" andModel:@"Prefect" andYear:1946];

Implementing Methods

Together, a method file and a header file pair store all the information needed to implement a class and announce it to the rest of an application. The implementation section of a class definition provides the code that implements functionality. This source is usually placed in an .m (for “method”) file.

Listing 3-2 shows the implementation for the Car class example. It codes all three methods declared in the header file from Listing 3-1 and adds a fourth. This extra method redefines init. The Car version of init sets the make and model of the car to nil, which is the NULL pointer for Objective-C objects. It also initializes the year of the car to 1901.

The special variable self refers to the object that is implementing the method. That object is also called the “receiver” (that is, the object that receives the message). This variable is made available by the underlying Objective-C runtime system. In this case, self refers to the current instance of the Car class. Calling [self message] tells Objective-C to send a message to the object that is currently executing the method.

Several things are notable about the init method seen here. First, the method returns a value, which is typed to (id). As mentioned earlier in this chapter, the id type is more or less equivalent to (NSObject *), although it’s theoretically slightly more generic than that. It can point to any object of any class (including Class objects themselves). You return results the same way you would in C, using return. The goal of init is to return a properly initialized version of the receiver via return self.

Second, the method calls [super init]. This tells Objective-C to send a message to a different implementation, namely the one defined in the object’s superclass. The superclass of Car is NSObject, as shown in Listing 3-1. This call says, “Please perform the initialization that is normally done by my parent class before I add my custom behavior.” Calling a superclass’s implementation before adding new behavior demonstrates an important practice in Objective-C programming.

Finally, notice the check for if (!self). In rare instances, memory issues arise. In such a case, the call to [super init] returns nil. If so, this init method returns before setting any instance variables. Since a nil object does not point to allocated memory, you cannot access instance variables within nil.

As for the other methods, they use year, make, and model as if they were locally declared variables. As instance variables, they are defined within the context of the current object and can be set and read as shown in this example. The UTF8String method that is sent to the make and model instance variables converts these NSString objects into C strings, which can be printed using the %s format specifier.

Listing 3-2. The Car Class Implementation (Car.m)

#import "Car.h"

@implementation Car
- (id) init
{
    self = [super init];
    if (!self) return nil;

    // These initial nil assignments are not really needed.
    // All instance variables are initialized to zero by alloc.
    // Here is where you would perform any real assignments.
    make = nil;
    model = nil;
    year = 1901;

    return self;
}

- (void) setMake:(NSString *) aMake andModel:(NSString *) aModel
    andYear: (int) aYear
{
    // Note that this does not yet handle memory management properly
    // The Car object does not retain these items, which may cause
    // memory errors down the line
    make = aMake;
    model = aModel;
    year = aYear;
}

- (void) printCarInfo
{
    if (!make) return;
    if (!model) return;

    printf("Car Info\n");
    printf("Make: %s\n", [make UTF8String]);
    printf("Model: %s\n", [model UTF8String]);
    printf("Year: %d\n", year);
}

- (int) year
{
    return year;
}
@end

Class Methods

Class methods are defined using a plus (+) prefix rather than a hyphen (-). They are declared and implemented in the same way as instance methods. For example, you might add the following method declaration to your interface:

+ (NSString *) motto;

Then you could code it up in your implementation:

+ (NSString *) motto
{
    return(@"Ford Prefects are Mostly Harmless");
}

Class methods differ from instance methods in that they generally cannot use state. They are called on the Class object itself, which does not have access to instance variables. That is, they have no access to an instance’s instance variables (hence the name) because those elements are only created when instantiated objects are allocated from memory.

So why use class methods at all? The answer is threefold. First, class methods produce results without having to instantiate an actual object. This motto method produces a hard-coded result that does not depend on access to instance variables. Convenience methods such as this often have a better place as classes rather than instance methods.

You might imagine a class that handles geometric operations. The class could implement a conversion between radians and angles without needing an instance (for example, [GeometryClass convertAngleToRadians:theta];). Simple C functions declared in header files also provide a good match to this need.

The second reason is that class methods can hide a singleton. Singletons refer to statically allocated instances. The iOS SDK offers several of these. For example, [UIApplication sharedApplication] returns a pointer to the singleton object that is your application. [UIDevice currentDevice] retrieves an object representing the hardware platform you’re working on.

Combining a class method with a singleton lets you access that static instance anywhere in your application. You don’t need a pointer to the object or an instance variable that stores it. The class method pulls that object’s reference for you and returns it on demand.

Third, class methods tie into memory management schemes. Consider allocating a new NSArray. You do so via [[NSArray alloc] init] or you can use [NSArray array]. This latter class method returns an array object that has been initialized and set for autorelease. As you read about later in this chapter, Apple has provided a standard about class methods that create objects. They always return those objects to you already autoreleased. Because of that, this class method pattern is a fundamental part of the standard iOS memory management system.

Fast Enumeration

Fast enumeration was introduced in Objective-C 2.0 and offers a simple and elegant way to enumerate through collections such as arrays and sets. It adds a for-loop that iterates through the collection using concise for/in syntax. The enumeration is very efficient, running quickly. It is also safe. Attempts to modify the collection as it’s being enumerated raise a runtime exception.

NSArray *colors = [NSArray arrayWithObjects:
    @"Black", @"Silver", @"Gray", nil];
for (NSString *color in colors)
    printf("Consider buying a %s car", [color UTF8String]);
  • + Share This
  • 🔖 Save To Your Account

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020