Application and operation loops

Run the loop

The application receives messages from the operating system about events such as mouse clicks and forwards them to the corresponding routine for processing. This process is called a run loop or an event loop.

Because Cocoa applications have GUI capabilities, once they start running, they always have a run loop, also known as the main run loop. Meanwhile, the application event processing or resource management function needs an object. Therefore, Mac OS provides an instance of NSApplication class, and iOS provides an instance of UIApplication class. The instance selects the corresponding processing object according to the event sent by the operating system and sends the corresponding message.

After the loop runs, when a new event message arrives and other processing has not finished, the application can put the event into a wait queue and execute it later in sequence. This property is well suited for asynchronous execution with multiple threads.

In the case of reference counting, the main loop generates an automatic release pool when it starts the event handling method and releases it when the method terminates. In the case of garbage collection, a garbage collector is started after an event is processed. The approach implemented in the application is basically to manage the automatic release pool itself, without worrying about when garbage collection will occur. Methods executed outside the main thread generate their own automatic release pool.

Timer object

Now let’s look at components that can send a specified message at a specified time or at a specified interval. Using this component flexibly makes it easy to perform operations that must be done in parallel.

The NSTimer class enables a specified message to be executed after a certain interval. The timer object is an instance that implements the NSTimer class.

The use of timer must have a running loop. After running the loop register timer, when the specified time is reached, the running loop will call the registered method to deal with it.

For more information about NSTimer, see the documentation.

Delayed execution of messages

Here’s how to execute a message after a period of time. This method is defined by NSObject and is available to all objects. Similarly, delayed execution also requires a running loop.

– (void)performSelector:(SEL)aSelector withObject:(nullableid)anArgument afterDelay:(NSTimeInterval)delay

// The message specified by aSelector will not be sent to anArgument until at least a delay of seconds after the message is sent.

+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector withObject:(id)anArgument

// Cancel the previously executed request.

entrust

The concept of delegation

When an object needs to change or add new functionality based on its purpose, a special consulted object is referred to in order to perform the newly added processing. This object is called a delegate. Delegates can be allocated dynamically at run time.

Delegation is a typical design pattern in which objects share functions and work cooperatively. In object-oriented terms, delegation can generally be interpreted as “a way for one object to receive a message that cannot be processed by another object”.

Delegates in the Cocoa environment

In the Cocoa environment, a delegate is an object that an application “adds” to add the necessary processing.

Delegates are highly reusable and effective in classes that are used as components. By using delegates, you can add independent functionality to software without compromising the independence of the original class.

An object does not have to have only one delegate; in some cases, an object can have multiple delegates.

To some extent, the same effect can be achieved using inheritance, but inheritance cannot be flexibly allocated at run time. Inheritance and delegation must be used separately, but delegates have many advantages that inheritance does not.

Delegate setup and protocol

The method to set the delegate and return the delegate uses the following function:

– (void)setDelegate:(id)anObject

// Set the parameter object to delegate. Generally, you do not need to retain the parameter object. Is a protocol that explicitly calls a delegate.

– (id)delegate

// Return the accepted delegate object.

In actual programming, in addition to focusing on the various methods that can be called, you also need to pay attention to what you can do with delegates.

If you want to use an object as a delegate, you need to declare the protocol for using the delegate in the interface section of that class. A good way to do this is to define categories that implement delegate methods. Furthermore, an object can be a delegate for multiple classes. Multiple corresponding protocols will be used at this point.

When declaring a delegate protocol, you must specify the @optional option in almost all methods. The object holding the delegate checks the messages that the delegate can handle at run time. Messages that are not implemented in the delegate are not sent. So the delegate object only needs to implement the corresponding processing method.

In addition, since sending messages to delegates in some cases presupposes the existence of a running loop, we need to pay attention to generating command-line programs.

Custom classes can also have delegate functionality, but it is not easy to implement. You implement it using respondsToSelector: and so on to check if you can handle a message.

notice

The concept of notification and notification center

In object-oriented programs, it is also sometimes necessary to notify multiple objects of events that occur.

In the Foundation framework, in order to perform an action, a program needs to notify multiple objects of that action. This method of sending messages is called notification.

The notification center object is provided within the program. (Notification Center) this object. The object to which the notification is expected registers the desired notification with the notification center in advance. There are multiple types of notifications, each marked by a notification name, and you can also define a new notification name.

An object sends a message sending request to the notification center, which is called a send (POST) notification. As long as the object is registered with the notification, the notification center will push the message.

The sending target, that is, the object registered in the notification center, is called an observer. When an object registers itself as an observer in the notification center, it specifies what name to receive notifications and what selector messages. Also, you can specify that only notifications sent by specific objects (POST) will be received. It doesn’t matter if there are many observers or none at all.

Any object is free to use the notification sending mechanism and does not need to be registered in the notification center. All the two must share is the name of the notification.

Such a mechanism allows messages to be sent to multiple objects without compromising the independence between the object sending the notification and the observer receiving the notification.

Multicast is the communication form in which an object sends messages to a specific number of objects, and brodcast is the communication form in which an object sends messages to a specific number of objects.

Notify the object

When a message is sent to the notification center, the necessary information is gathered in the NSNotification class instance and sent to the notification center. This object is called a notification object, or simply a notification. When an observer gets a message from the notification center, it also gets the attached notification object.

The notification object contains the following information:

Name:

A short text used to identify notifications. Take it out with the following message.

– (NSString *)name

Object:

The object of the accompanying message sent with the notification. Mostly objects that send notifications, and can be nil. Take it out with the following message.

– (id)object

User dictionary (userInfo)

The NSDictionary is used for passing various information related to notifications. Take it out with the following message.

– (NSDictionary *)userInfo

Because notification objects are automatically created when messages are sent to the notification center, there is no need to create them yourself. To create a notification object, you can use any of the following class methods of NSNotification.

+ (id)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)userInfo

// Generate temporary notification objects by specifying the notification name, object, and user dictionary.

+ (id)notificationWithName:(NSString *)aName obect:(id)anObject

// Generate temporary notification objects by specifying the notification name and object. User information dictionary is nil.

Notification center

The notification center uses the class interface of NSNotificationCenter.

1. Default notification center

Each process prepares a notification center in advance and generally does not need to create it itself. This is the default notification center, which can be obtained using the following class method.

+ (id)defaultCenter

2. Notification sending

Related method reference documents

3. Observer registration

Related method reference documents

4. Delete the observer registration

Related method reference documents

There is a need for extra attention to memory management. First, in the case of reference counting management, the notification center does not retain the observer and send the source object when registering the observer. Therefore, do remove the Settings from the notification center before releasing these objects. If not, the pointer to the freed object will be null.

When using the garbage collection mechanism, the observer and sending source objects are registered with the notification center using weak references. There is no need to explicitly delete the observer’s registration.

Notice the queue

Notification queue is to temporarily store the notification object in the waiting queue, and then send messages to the notification center according to the principle of FIFO. Notification queues are implemented via NSNotificationQueue. For details, see related documents.

1. Send it asynchronously

The notification is appended to the queue and then sent after either the running loop completes its current processing or the input in the running loop has been processed. Using this method, you can simply terminate the method appended to the queue and proceed to the next item. In this way, the notification is sent after a sequence of processing. This method is also called asychronous sending. The normal handling is synchronous send.

2. Merge the same notifications

When there are identical notifications in the notification queue, they are merged into one to remove unwanted notifications.

Definition of notification name or exception name:

When you customize the use of notification names or exception names, you usually use global variable or macro names instead of a constant string.

A chain reaction

Overview of reaction chain

Responder chain is a way of automatically sending messages between hierarchical GUI components.

The candidate component objects that process the message are strung together like beads, passing the message to one of the objects in between, passing the message back to the next object until an object that can process the message is found. This configuration is called a chain.

In Mac OS, components such as keys, sliders, and text fields, as well as objects such as forms and panels, are subclasses of the NSResponder class of the Application framework. Again, in iOS it’s a subclass of UIResponder from UIKit framework.

In each form, the object to which the message is initially sent is called the first responder. The first responders are the most recent objects selected by the cursor.

Reaction chain in application

On the Mac OS, the window at the front of the application window is called the main window. Among other Windows, including panels and so on, the front-most window is called the key window. The main window can also be a key window.

The search within the chain starts with the first responder in the key window. If the key window cannot be found, if there are other main Windows, the reaction chain of the main window will be searched in the same way.

Sometimes messages end up being passed to the interface of NSApplication (the class that manages the entire application) when the main window can’t handle them either. In this way, messages that cannot be processed are ignored or a warning sound is sounded.

On iOS, the class UIView that represents the drawing area is a superclass of other GUI components and a subclass of UIResponder that represents the responder. Interfaces consist of a window (UIWindow class), a UIView class, and its subclasses GUI components that overlap hierarchically. UIKit automatically identifies any key or text field as the first responder. Messages that cannot be processed by the first responder are delivered sequentially to Windows and even references (UIApplication classes) along overlapping GUI components.

In a Cocoa environment, knowledge of reaction chains is required to build applications that contain guIs. For details, see “Cocoa Event-Handing Guide” “Event-Handing Guide for iOS”.

Message transfer

Composition of message forwarding

A runtime error usually occurs when a message is sent to an object that does not implement the message method. However, it is possible to forward messages that cannot be processed to other objects.

Send a message to the appropriate receiver. If the receiver does not implement a way to handle the message, the runtime system sends the following message to the receiver.

– (void)forwardInvocation:(NSInvocation *)anInvocation

// This method is defined in NSObject and can be handled by all objects. In NSObject, this method can call the following methods

– (void)doesNotRecognizeSelector:(SEL)aSelector

/ / generates an error message, said abnormal NSInvalidArgumentException, unable to process parameters corresponding message selector.

That is, as long as the receiver redefines the forwardInvocation: method, when a message is sent that cannot be processed, it can either be forwarded to another object or perform error handling itself.

Information needed for message forwarding

The NSInvocation object stores the target, selector, parameters, and all the elements required for message delivery.

The following are the main methods of the NSInvocation class.

– (SEL)selector

// Return the set selector

– (id)target

// Returns the set target

– (void)invokeWithTarget:(id)anObject

// Send a message to the target parameter object representing the receiver. Returns the result of the message to the source sender.

Definition of message forwarding

Using the NSInvocation message above, forwardInvocation: can be redefined for message forwarding. However, only methods with a fixed number of arguments can be forwarded.

For example, investigate whether the unprocessed message can be forwarded to the object fellow, and if it cannot be forwarded, it can be forwarded to the superclass for processing, which can be defined as follows:

– (void)forwardInvocation:(NSInvocation *)anInvocation {

SELsel = [anInvocation selector];

if([fellow respondToSelector:sel])

[anInvocation invokeWithTarget:fellow];

else

[superforwardInvocation];

}

In order for the run-time system to generate the NSInvocation instance using the object information from the relay destination, the returned Method Signature object must be redefined.

To represent method signatures, an NSMethodSignature class is defined. Its objects hold the parameters and return values of the method, but the program does not process them outside of message forwarding or communication.

Returns the method signature method in methodSignatureForSelector: and defined in the NSObject. For example, if the transfer destination is Fellow, it can be redefined as follows.

– (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

if([superrespondsToSelector:aSelector])

return[supermethodSignatureForSelector:aSelector];

return[fellow methodSignatureForSelector:aSelector];

}

However, messages processed using a forwarding method cannot be called by respondsToSelector: etc. Methods such as respondsToSelector must be redefined when we need to know whether the message is a message that the target object can handle.

Disable messages

As mentioned above, the method doesNotRecognizedSelector: generated by the said news can’t handle an exception.

This feature allows you to define runtime errors when a method is used. A typical example would be to write down a method defined with a superclass that is not available in a subclass.

For example, if you want to disallow the setSize: method, you can define it as follows. Here _cmd is the hidden parameter of the method and represents the selector of the method. So it’s the same thing to write at sign selector(setSize:).

– (void)setSize:(NSSize *)size {

[selfdoesNotRecognizeSelector:_cmd];

}