Explore messaging mechanisms in iOS development

Source: Internet
Author: User

Note 1: This article is translated from communication Patterns by broken ship.

Each application is more or less composed of loosely coupled objects that need to be delivered in order to accomplish the task well. This article describes all of the messaging mechanisms available, and provides examples of how these mechanisms are used in the Apple framework, as well as some best practice recommendations that tell you when to choose what mechanism to use.

Although the topic for this issue is about the foundation framework, some messaging mechanisms that go beyond the scope of the foundation framework (KVO and notification) are described in this article, along with delegation , Block and Target-action.

In most cases, it is clear what mechanism to use for message passing, and of course, what mechanism to use in some cases does not have a clear answer, and you need to try it yourself.

In this article, it is often mentioned 接收者[recipient] and 发送者[sender] . What exactly is meant by the message passing mechanism, we can explain by an example: A table view is the sender, and its delegate is the receiver. The Core Data managed object context is the sender of the notification, and the body that obtains the notification is the recipient. A slider (slider) is the sender of the action message, and the responder that corresponds to implementing the action in the code is the recipient. An attribute in an object supports KVO, so who modifies the value, who is the sender, and the corresponding observer (Observer) is the recipient.

The available mechanisms

First, let's look at the specific characteristics of each mechanism. In the next section, I'll combine a flowchart to show you how to choose the right messaging mechanism in specific situations. Finally, some examples from the Apple framework will be introduced, explaining why a fixed mechanism should be chosen in a certain situation.

KVO

KVO provides a mechanism for notifying observers of these values when a property value in the object has changed. The implementation of KVO is contained within the foundation, and many of the frameworks built on the foundation are dependent on the KVO. To learn more about how to use KVO, you can read the KVO and KVC articles written by Daniel in this issue.

If you are interested in changing the value of an object, you can use the KVO message passing mechanism. There are two requirements, first, the receiver (the message that will receive a change in value) must know the sender (the object whose value will change). In addition, the receiver also needs to know the life cycle of the sender, because the viewer's registration needs to be canceled before the sender object is destroyed. If both requirements are met, the message can be 1-to-many during messaging (multiple observers can register values in an object).

If you plan to use KVO on the core data object, you need to know that this is a bit different from the general KVO usage. That is the failure mechanism that must be combined with core data (faulting mechanism), and once the core data fails, it will trigger the observer for its properties (even if the property values have not changed).

Notification

Notification (notifacation) is a good mechanism for message delivery in unrelated two-part code, and it can broadcast messages. In particular, you want to deliver rich information, and you don't necessarily expect anyone to care about this message.

Notifications can be used to send arbitrary messages, even a userinfo dictionary, or a subclass of Nsnotifacation. The uniqueness of the notice is that both the sender and the receiver do not need to know each other. This enables the delivery of messages between very loosely coupled modules. Remember, this messaging mechanism is one-way, and you can't reply to a message as a recipient.

Delegation

In the Apple framework, the delegation pattern is widely used. Delegation allows us to customize the behavior of an object and to receive certain events. In order to use the delegation mode, the sender of the message needs to know the recipient of the Message (delegate), which in turn is not necessary. The sender and receiver here are relatively loosely coupled because the sender only knows that its delegate is following a particular protocol.

The delegate protocol can define any method, so you can define exactly what type you want. You can process the message content in the form of a function parameter, and the delegate can also respond to the sender in the form of a return value. Delegation is a very flexible and straightforward way to do this only if you need to deliver messages between the relatively close two modules.

However, the excessive use of delegation also has a certain risk, if the two objects are more tightly coupled, can not be independent of each other, then there is no need to use the delegate protocol, in this case, the object can know the type of each other, and then directly to the message delivery. such as Uicollectionviewlayout and nsurlsessionconfiguration.

Block

Block is relatively new technology, which first appears in OS X 10.6 and iOS 4. In general, block can satisfy the message passing mechanism implemented with delegation. However, both of these mechanisms have their own needs and advantages.

When block is not considered, it is generally considered that the block is very susceptible to retain rings. A potential retain loop occurs if the sender needs to Reatain block and cannot ensure that the reference is nil.

Suppose we want to implement a table view and use block instead of delegate as the selection callback, as follows:

    1. Self.myTableView.selectionHandler = ^void (Nsindexpath *selectedindexpath) {
    2. //Handle selection ...
    3. };

The problem with the above code is that self retain the table view, and table view can then retain block by using block. And table view can't get this quote nil, because it doesn't know when it's not going to need this block. If we can not guarantee to break the retain ring, and we need to retain sender, this time block is not a good choice.

Nsoperation can use block very well, because it can break the retain ring at some time:

    1. Self.queue = [[Nsoperationqueue alloc] init];
    2. Myoperation *operation = [[Myoperation alloc] init];
    3. Operation.completionblock = ^{
    4. [Self finishedoperation];
    5. };
    6. [Self.queue addoperation:operation];

At first glance this seems to be a retain ring: the self retain queue,queue retain operation, operation retain the completion block, and completion Blockretain the self. However, when operation is added to the queue, it causes the operation to be executed at some point and then removed from the queue (if not executed, there is a big problem). The retain ring was broken after a single queue was removed from the operation.

Another example: Here is the implementation of a video encoder class, which has a method named Encodewithcompletionhandler:. To avoid the retain ring, we need to make sure that the Encoder object is able to nil its reference to the block at a certain time. Its internal code is as follows:

  1. @interface Encoder ()
  2. @property (nonatomic, copy) Void (^completionhandler) ();
  3. @end
  4. @implementation Encoder
  5. -(void) Encodewithcompletionhandler: (void (^) ()) handler
  6. {
  7. Self.completionhandler = handler;
  8. //Do the asynchronous processing ...
  9. }
  10. This one would be called once the job was done
  11. -(void) finishedencoding
  12. {
  13. Self.completionhandler ();
  14. Self.completionhandler = nil; //<-Don ' t forget this!
  15. }
  16. @end

In the above code, once the encoding task is complete, the complietion block is called and the reference is nil.

If the message we send is a one-time (specific call to a method), because it breaks the potential retain ring, using block is a good choice. In addition, if you want to make your code more readable and consistent, it's best to use block. According to this idea, block can often be used for completion handler, error handler, etc.

Target-action

Target-action is primarily used in messages that need to be passed in response to user interface events. This mechanism is supported by Uicontrol in iOS and Nscontrol/nscell in Mac. Target-action establishes a very loose coupling between the sender and receiver of the message. The recipient of the message does not know the sender, or even the sender of the message does not need to know the recipient of the message beforehand. If Target is nil,action is passed in the response chain (responder chain), it is known to find an object that can respond to Aciton. In iOS, each control can have multiple target-action associated with it.

One limitation of the mechanism based on target-action message delivery is that messages sent cannot carry custom payload. In the action method of the Mac, the receiver is always placed in the first parameter. In iOS, the sender and the event that triggered the action can optionally be used as parameters. In addition, there is no other way to control the content of the Send action message.

Make the right choice

Based on the results discussed above, here I draw a flowchart to help us decide when to use what messaging mechanism to make better decisions. Advice: The suggestions in the flowchart are not the final answer; there may be other options that can still be achieved. But in most cases this diagram will guide you in making the right decision.

, there are some details that need to be explained in a more recent step:

There's a box in it saying: Sender is KVO compliant (sender supports compliant). This not only means that when the value changes, the sender sends a KVO notification, and the observer needs to know the sender's life cycle. If the sender is stored in a weak attribute, then the sender is likely to be nil, causing the observer to occur leak.

Another box at the bottom says: message is direct response to method call (the message responds directly in the method's calling code). This means that the code that processes the message is in the same place as the method's calling code.

Finally, in the lower left corner, in the judgment state of a decision question: Sender can guarantee to nil out of reference to block? (Can the sender make sure that nil falls to the block reference?) This actually involves the potential retain ring that we discussed before in the block-based APIs. When using block, if the sender cannot guarantee that a reference to the block can be lost at some point, then it will encounter the problem of the retain ring.

Framework Example

In this section, we'll look at some examples from the Apple framework to see what causes Apple to make a choice before actually using some kind of mechanism.

KVO

Nsoperationqueue is that Lion gave kvo to observe changes in Operation State properties in the queue (isfinished, isexecuting, iscancelled). When the state has changed, the queue is subject to a KVO notification. Why would operationqueue use KVO?

The recipient of the message (Operation queue) knows the sender (Opertation) explicitly, as well as the retain to control the life cycle of the operation. In addition, in this case, only one-way messaging mechanism is required. Of course, if you consider this: if the operation queue only cares about changes in operation values, it may not be enough to persuade everyone to use KVO. But at least we can understand this: what mechanism can be used to message the change of value.

Of course KVO is not the only choice. We can design this: Operation queue as Operation's delegate,operation will call like Operationdidfinish: or operationdidbeginexecuting: Such a method To pass its state to the queue. This is inconvenient because operation needs to save its State property and call these delegate methods again. In addition, because the queue cannot actively acquire state information, the queue must also hold all operation state.

Notifications

Core data uses notification to pass events (such as a managed object context internal change--nsmanagedobjectcontextdidchangenotification).

Change notification is issued by managed object context, so we are not sure that the recipient of the message must know the sender. Notification is the best choice if the message is not a UI event, and it is possible that multiple recipients are interested in the message and that the message is passed in a one-way (one-way communication channel).

Delegation

The delegate of Table view has many functions, from the management of accessory view to the tracking of cell display in the screen, all with delegate credit. For example, let's look at Tableview:didselectrowatindexpath: methods. Why do you want to do this in a delegate call? And why not use the target-action way?

As we saw in the flowchart, when using target-action, you cannot pass custom data. When you select a cell in Table view, collection view not only needs to tell us that a cell is selected, but also to tell us which cell is selected (index path). In such a way, you can see from the flowchart that you should use the delegation mechanism.

What if the message is not included with the index path of the selected cell, but whenever the selected item changes, we take the initiative to get information about the selected cell in the table view? In fact, this can be very troublesome, because in this way, we have to remember the current selection related data in order to know the selected cell.

Similarly, although we can also observe the value of the index paths property of the selected item in table view, when the value changes, a notification of the change of the selected item is obtained. However, we will encounter the same problem as above: how do we know about the selected item without making any records?

Blocks

For the introduction of block, let's take a look at [nsurlsession Datataskwithurl:completionhandler:]. Returning from the URL loading system to the caller, how does this process convey the message? First, as the caller of this API, we know the sender of the message, but we don't retain the sender. In addition, this is a one-way message delivery-Call Datataskwithurl directly: method. If you follow this line of thinking against the flowchart, we will find that we should use a mechanism based on block message passing.

Are there other optional mechanisms? Of course, Apple's own nsurlconnection is the best example. Nsurlconnection existed before the block was introduced, so it did not use block for message delivery, but instead used the delegation mechanism. When the block appears, Apple adds the SendAsynchronousRequest:queue:completionHandler: Method (OSX 10.7 IOS 5) to the nsurlconnection, so if it's a simple task, You don't have to use delegate.

In OS X 10.9 and IOS 7, Apple introduced a very modern api:nsurlsession, which uses block as the messaging mechanism (Nsurlsession still has a delegate, but for other purposes).

Target-action

One of the most obvious places for target-action is the button. button In addition to sending a click event, there is no need to send a farewell message. So target-action is the best choice in the process of user interface event passing.

If Taget has been explicitly specified, then the action message is sent back directly to the specified object. If Taget is a nil,action message, it will find an object in the response chain that can handle the message in a bubbling fashion. At this point, we have a completely decoupled messaging mechanism-the sender does not need to know the receiver, and some other information.

Target-action is well suited for events in the user interface. There is no other appropriate messaging mechanism available to provide the same functionality. Although notification is closest to this decoupling relationship between sender and receiver, target-action can be used in the response chain (responder chain)-only one object gets the action and responds, and the action can be passed in the response chain, Until you encounter an object that can respond to the action.

Summary

The first contact with these mechanisms is that they can be used for message passing between two objects. But if you think about it, you will find that each has its own needs and functions.

The decision-making flowchart given in this paper can provide a reference for the mechanism we choose to use, but the plan given here is not the final answer, and many places need to be practiced in person.

Note: This article is transferred from http://mobile.51cto.com/hot-431125.htm (if there is infringement, please inform)

Explore messaging mechanisms in iOS development

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.