When we write software for OS X or iOS, we spend most of our time working with objects. Objects in Objective-C are similar to objects in other object-oriented languages: they encapsulate data and data-related behavior.

To build an App is to build an ecosystem of interconnected objects. In this system, objects interact with each other to solve specific problems – such as presenting a visual interface, responding to user input, or storing information. For OS X and iOS development, we don’t have to spend time solving every problem. Cocoa(OS X) and Cocoa Touch(iOS) have plenty of objects ready for us to solve problems.

There are some system objects that you can use directly, such as basic data types like strings and numbers, as well as Buttons and TableViews. Still others require a combination of custom code to implement specified requirements. How to customize the object, how to combine the user-defined object with the object provided by the system in the best way to give our App unique functions and features, is the problem we need to think about in the process of App development.

In object-oriented programming, an object is an instance of a class. This chapter focuses on defining an Objective-C class that describes how we expect the class and its instances to be used by declaring interfaces. The interface contains a list of messages that this class can accept, so we also need to provide a class implementation that implements the snippet of code that responds to the message.

Classes are templates/blueprints for objects

A class describes the behavior and properties of an object. Like a string object (in Objective-C, an instance of NSString), the NSString class provides a number of methods to examine and convert its internal characters. Similarly, objects describing numbers (NSNumbers) provide various methods for manipulating numbers, such as converting internal values to other numeric types.

When building from the same template/blueprint, each building has exactly the same structure. Each instance object of a class has the same properties and behavior. Every INSTANCE of NSString, even though its internal characters may be different, has the same method.

Certain objects are used in certain ways. A string object represents a string of characters, but we can use it without understanding its internal mechanism for storing characters. We also don’t need to understand the mechanics of character processing inside a string, but we do need to understand how to interact with a string object, such as how to get a character inside it, or how to get a new string object that converts the inner character to uppercase. In Objective-C, the *** class interface *** specifies how certain objects interact with other objects. In other words, a class interface defines the public interface of the class instance object and other parts.

Mutability determines whether an object value can be changed

Objects defined by some classes are immutable. This means that the contents of such objects must be set at creation and cannot be changed later by other objects. In Objective-C, all NSString objects and all NSNumber objects are immutable. If we need to represent a different value, we can only create a new NSNumber object.

Some immutable classes also provide a mutable version. You can use the NSMutableString class if you need to change the contents of a string dynamically at run time, such as adding characters to the end of the string based on the contents of the response after a network request. An instance of this class is mostly the same as the NSString class, except that it can dynamically change the contents of a string.

Although NSString and NSMutableStriing are different classes, they have a lot in common. So it makes more sense to use inheritance than to write two completely different classes.

Inheritance (Inherit)

In nature, taxonomy divides animals into families/genera/species. The division is hierarchical, for example, multiple species may belong to the same genus, and multiple species may belong to the same family.

Human (Gorilla), chimpanzee (Orangutan) and other primate species are different species. Although they are different species, even different species. But they belong to the same family, Hominidae.

In the world of object-oriented programming, objects are categorized hierarchically. Unlike natural taxonomy, which is divided into families/genera/species, object orientation is simply divided by Class. Just as a person inherits hominid characteristics, a class can inherit characteristics from its parent.

When a class inherits from another class, the subclass inherits all the behaviors and properties defined by the parent class. Subclasses can also define their own unique behaviors and attributes, or Override the behavior of their parent class.

In the objective-C string class example, as shown below, NSMutableString is derived from NSString. All of the functionality that NSString provides, NSMutableString is available. For example, get a string at a specified position/get an all uppercase string. But NSMutableString adds methods such as add, insert, replace, and delete substrings/characters.

The Root Class (Root class-nsobject) provides the basic capabilities

Just as all living things have the quality of life, all objective-C classes have some common characteristics.

When an Objective-C object needs to interact with objects of other classes, it expects the other classes to provide certain basic features and behaviors. Therefore, Objective-C defines a Root Class called NSObject from which most objective-C classes inherit. When one object encounters another, it expects them to interact with each other through the basic behavior defined in NSObject.

When we customize a class, we should at least have it inherit from NSObject. Generally speaking, we should find a class in the Cocoa/Cocoa Touch framework to inherit from that class that gives us the functionality we need most.

For example, if we want to customize a Button in an iOS App. The UIButton class does not provide enough custom properties to satisfy our needs. We should create a class that inherits from UIButton instead of directly inheriting from NSObject. If we inherit NSObject, then in order to implement our needs, we need to re-implement the complex visuals and interaction methods that we’ve already implemented in UIButton, but if we inherit UIButton directly, our subclasses automatically get all the functionality of UIButton, and not only that, If there are further enhancements or Bug fixes to UIButton in the future, our subclasses will benefit.

The UIButton class inherits from UIControl, which describes all the basic behavior related to user interaction on iOS. UIControl class inherits from UIView, which gives it the ability to display on screen. The UIView class inherits from UIResponder, which provides functions that respond to user input, such as clicks, gestures, or shakes. UIResponder ultimately inherits from NSObject, as shown below.

As you can see from this inheritance chain, any class that inherits from UIButton can inherit not only the capabilities defined inside UIButton, but also the capabilities of all its parent classes. We end up with a class that describes such an object: Behaves like a button (UIButton/UIControl), can be displayed on screen (UIView), can respond to user input (UIResponder), and can interact with other Cocoa Touch objects (NSObject).

In order for the class we define to do its job properly, it is critical to keep inheritance chains in mind.

The Interface of the class defines the expected interaction

One of the great things about object-oriented languages is that when we want to use a class, we just need to know how to interact with its objects. More specifically, objects should hide implementation details from their internal implementations.

Assuming we use UIButton, we don’t need to care how each pixel is displayed on the screen. We just need to know how we can change the current properties, such as the title and color of the button. When we add this button to the interface, it will automatically display correctly on the screen.

When we customize a class, we first need to consider the external properties and behavior. Which properties are open to the outside world? Should outsiders be allowed to modify these properties? How do objects of other classes interact with objects of our class? This information determines how we define our class’s interfaces — interfaces define how we expect other objects to interact with our class objects. The interface of a class and the internal implementation of a class are described separately. In Objective-C, interfaces and implementations are often placed in two separate files, and we only need to expose the interface files.

Defines the interface

The objective-C syntax for defining a class Interface is as follows:

@interface SimpleClass : NSObject
 
@end
Copy the code

This example defines a class called SimpleClass, which inherits from NSObject.

Public properties and behaviors are defined in the @ Interface declaration. In this example, no public properties/behaviors are defined, so SimpleClass simply inherits NSObject’s behavior.

Properties controls the acquisition of an object’s value

Objects often provide properties. If you want to define a class that represents information about a person, you might need to define string attributes to represent the person’s first and last name.

Declarations of these attributes should be added inside the interface.

@interface Person : NSObject
 
@property NSString *firstName;
@property NSString *lastName;
 
@end
Copy the code

In this example, the Person class declares two public properties, both of which are instances of the NSString class.

These properties are objective-C objects, so we use * to make it look like a C pointer. They are declared just like C variables are declared, so don’t forget the end of the declaration; .

If you wanted to add a birth year attribute, you could add it like this:

@property NSNumber *yearOfBirth;
Copy the code

Since only one value is stored, we can replace it with C’s basic numeric type int

@property int yearOfBirth;
Copy the code

Attributes use properties to represent how data is read, written, and stored.

In the examples so far, all of the declared properties are fully externally accessible. That is, other objects can read and write these properties.

In some cases, we don’t want some properties to change. For the Person class, if we don’t want the firstName and lastName attributes to be modified, I can use readonly to limit the attributes to be readable but not writable.

Objective-c attribute declarations can indicate whether the attribute is read-only by adding a readonly attribute.

@interface Person : NSObject
@property (readonly) NSString *firstName;
@property (readonly) NSString *lastName;
@end
Copy the code

Attributes of a property can be specified in parentheses after the @property. // Todo: Add a link.

Use Method declarations to represent messages that objects can accept

The examples so far describe a Model object in a typical Model-View-Controller Model — an object primarily used for data encapsulation. In the case of the Person class, you probably don’t need to add more than just get two attributes. But in most classes, you add method declarations in addition to attributes.

As mentioned above, Objective-C is made up of a network of objects. It is important to note that the interaction between these objects is achieved by sending Messages. In Objective-C, one object sends a message to another object by Calling a method.

Objective-c Methods are conceptually similar to Functions in C and other languages, even though their syntax is quite different. A C function declaration looks like this:

void SomeFunction();
Copy the code

The equivalent Objective-C method is declared as follows:

- (void)someMethod;
Copy the code

In this case, the method has no parameters. The void keyword in C is enclosed in parentheses before the declaration, indicating that the method does not return any value.

The method that precedes the method – indicating that the method is an instance method – can be called by an instance object of that class. Its counterpart is the class method, which is a method that is mobilized by the class itself. // TODO: Add a link.

As with C function Prototypes, method declarations within objective-C class interfaces need a semicolon; At the end.

Methods can accept arguments

When defining a method that takes one or more arguments, the objective-C syntax is quite different from that of classical C functions.

For C functions, arguments are specified in parentheses, as follows:

void SomeFunction(SomeType value);
Copy the code

Objective-c method declarations use: arguments as part of the method name, as shown below:

- (void)someMethodWithValue:(SomeType)value;
Copy the code

Like the return value type, the parameter type is surrounded by parentheses (), just like the standard C-type conversion (C type-cast).

If you need to specify multiple parameters, the objective-C syntax is still quite different from THE C syntax. C functions wrap, use, and separate multiple functions with (), whereas in Objective-C, the function declaration for two arguments looks like this:

- (void)someMethodWithFirstValue:(SomeType)value1 secondValue:(AnotherType)value2;
Copy the code

In this example, value1 and value2 are formal parameters to get the values passed in the parameters in the implementation.

Some programming languages allow functions to define so-called named arguments. It is important to note that this feature is not allowed in Objective-C. The order of the arguments in the method call must be the same as the order of the arguments in the method declaration, and the secondValue: section in the method declaration is part of the method name.

someMethodWithFirstValue:secondValue:
Copy the code

This feature makes Objective-C very readable, since parameter values are passed in the method next to the method name of the associated party inline.

Note: Value1 and value2 here are not strictly part of the method declaration. That is, this part does not have to use exactly the same name in the method declaration and method implementation. The only requirement is that the signature be consistent — the method name be the same and the parameter and return value type be the same. For example, the following method has the same signature as the above method:

- (void)someMethodWithFirstValue:(SomeType)info1 secondValue:(AnotherType)info2;
Copy the code

The following two methods have different signatures:

- (void)someMethodWithFirstValue:(SomeType)info1 anotherValue:(AnotherType)info2;
- (void)someMethodWithFirstValue:(SomeType)info1 secondValue:(YetAnotherType)info2;
Copy the code

The class name must be unique

Each class must have a unique class name, even across the Library/Framework. If duplicate class names are created, a compile-time error will be generated.

Therefore, it is recommended to use class name prefixes of three or more letters. Examples following this document will use class name prefixes as follows:

@interface XYZPerson : NSObject
@property (readonly) NSString *firstName;
@property (readonly) NSString *lastName;
@end
Copy the code

Note: You may be wondering why so many of the classes we use use the NS prefix. This is because of the past history of Cocoa and Cocoa Touch. Cocoa was originally born as a framework for the NeXTStep operating system. When Apple bought NeXT in 1996, most of NeXTStep was incorporated into OS X, which included existing class names. Cocoa Touch is a port of Cocoa to the iOS platform. Many classes are common to Cocoa and Cocoa Touch, although there are a large number of platform-specific classes. Some two-letter prefixes like NS and UI are reserved as keywords by Apple.

In contrast to class names, method and attribute names need only be unique in the class in which they are defined. Although every C function must have a unique name, it is perfectly acceptable to define the same name in multiple Objective-C classes. We cannot define a method more than once in the same class declaration, but when we want to override the parent class’s method, we must use the same method name as the parent class declaration.

Like method names, the attributes and instance variables of an object must be unique in the class defined. If global variables are defined, the names of these global variables must be unique within the App or project.

Use the Implementation of a class to provide the internal behavior of a class

When we define the interface of the class (including external attributes and methods), we need to implement the concrete behavior of the class through the Implementation of the class.

As mentioned earlier, the interface to a class is often placed in a separate file — a header file. A header file has a.h. extension and we keep the implementation of our Objective-C class in a.m file.

Whenever we define an interface in a header file, we need to tell the compiler to read the header file before compiling the implementation file. Objective-c provides a precompiled instruction, #import, to do this. This directive is similar to C’s #include directive, but #import ensures that each file is included only once at compile time.

The basic grammar

The basic syntax for class implementation is as follows:

#import "XYZPerson.h"
 
@implementation XYZPerson
 
@end
Copy the code

If we declare methods in the class interface, we need to implement the declared methods here.

Implementation method

For simple class interface declarations like this:

@interface XYZPerson : NSObject
- (void)sayHello;
@end
Copy the code

An implementation of a class might look like this:

#import "XYZPerson.h" @implementation XYZPerson - (void)sayHello { NSLog(@"Hello, World!" ); } @endCopy the code

This example uses the NSLog method to output strings in the console. Much like printf() in C, it can take multiple arguments, but the first argument must be of type Objective-C String.

The implementation of the method is similar to the definition of the C method, enclosing the related code with {}. In addition, the method name must be identical to its prototype, and the parameters and return value types must be exactly the same.

Objective-c, like C, is a case-sensitive language. Therefore, the following method:

- (void)sayhello {
}
Copy the code

The sayHello method is completely different from the previous one.

In general, method names should start with a lowercase letter. The convention in Objective-C is to use more descriptive method names. If the method name contains more than one word, use the camel name (capitalizing the first letter of each new word) to make the method name easier to read.

Another area to watch out for is whitespace characters. Whitespace characters are flexible in Objective-C. We can indent code using either the TAB character TAB or the space Spaces. And the open curly brace is usually exclusive, as shown below:

- (void)sayHello { NSLog(@"Hello, World!" ); }Copy the code

Apple’s developer tool XCode will automatically indent code based on user preference

Objective-c Classes are also objects

In Objective-C, every Class is an object of type Class. The Class classes do not declare attributes like the instance objects in the previous example, but they can accept Messages.

The classic use case for a Class method is as a Factory method, which provides a way to create and initialize objects. The NSString class, for example, has a number of factory methods that can either create an empty string object, or create a string object from a specific character:

+ (id)string; + (id)stringWithString:(NSString *)aString; + (id) stringWithFormat (nsstrings *) format,... ; + (id)stringWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error; + (id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;Copy the code

As you can see from the code above, class methods start with a +, unlike instance methods that start with a -.

Class method prototypes may be included in a Class’s interface, just as instance method prototypes are. Class methods and instance methods are implemented the same way, at @implementation.

Practice:

  1. Use XCode to create an inheritance fromNSObjecttheXYZPersonClass, containing the interface declaration of the class and the implementation file of the class.
  2. inXYZPersonClassfirstName.lastName, as well asNSDateThe type ofdateOfBirth.
  3. The statementsayHelloAnd implement it.
  4. Add a factory method declaration for the classperson.

Reference: Defining Classes