This series of articles is a record of my thinking process when learning relevant knowledge in the field. The correctness and rigor of the content are not guaranteed. If you find any problems, please point out and exchange them.
1. Introduction
I have read some articles about the interaction between objects on the Internet, some of which I think are quite agreeable, and some of which I feel are not ideal enough. I think many people will have their own opinions on this kind of content which is somewhat biased towards design. Personally, I am used to analyzing a problem or a type of problem from different perspectives, which is suitable for me. If you are interested, you can read on.
This article describes the event transfer between objects from different perspectives. Personally, I think the word event transfer is more suitable for my content, but I don’t use the word “interaction”, because the word is too broad.
2. Classification of event delivery
Taking on what has been said above, since it is transmission, we can establish a problem model for sender and receiver. The sender needs to transmit events or information to the receiver, and the receiver makes certain responses to it according to its own needs. It’s important to note that the objects we describe are basically iOS platform-specific, and of course most are generic.
First of all, we discuss how to classify event transmission. Classification needs to be established from different observation perspectives. Here, I divide it into two perspectives. The second is the design of the process, that is, how the object uses its envisaged process to transfer data at runtime. Here, some intuitive dependencies or common abstract designs are generally used. With this in mind, feeling leads to the heart of this article, which is finding the right event delivery design in the right scenario.
2.1 Coupling Relationship
It is possible for two objects to be coupled when they are connected. The intuitive idea is that the sender wants to pass events to the receiver and simply delivers them to it, so that the operation itself is not a problem, so that the explicit deterministic coupling between the two can occur. The reason why other types of looser coupling are designed is that the intuitive and simple way is simple, but it is not flexible enough. In modern software development, the complexity and scale of projects are increasing, and flexibility is an important reference to affect the quality of software and development efficiency.
-
Determine the type
Direct coupling occurs when the sender explicitly references the receiver’s type.
-
Abstract type
Abstract types In most object-oriented languages, there are two common manifestations of abstract types, Protocol and base classes, in Objective-C (Objective-C does not support language-level abstract class parts).
The effect of abstract types on coupling relationships is to reverse dependencies, evolving from senders directly dependent on receivers to senders dependent on abstractions and receivers dependent on abstractions. From the perspective of architecture hierarchy, it makes high-level components not directly dependent on low-level components, and it has better scalability from the perspective of coupling relationship.
-
The type has nothing to do
The first two methods distinguish the relationship according to the type of the object, while some methods of event delivery do not care about the type and pass the event through an intermediate layer design, but the receiver may need to accurately distinguish the type and parameter identification of the event when responding to the event. This approach addresses type dependence at compile time, but also introduces runtime maintenance issues.
Coupling of code in a project may be sneering, but coupling is not a problem in most cases, it is reasonable to distinguish the parts of the project code that should be coupled based on the actual situation, such as in a project developed according to the MVC pattern. We build directly on the ViewController using the actual type of the View, and try to keep the View loosely coupled to the ViewController, which in most cases is fine; In the case of two business components that need to be decoupled, even one-way dependencies are no longer appropriate, and a design like the middle tier is needed to decouple both ways.
2.2 Process Design
The design of event passing is riddled with all sorts of clever object combinations. When looking at event passing from a process perspective, different process designs often have their own appropriate scenarios, which is the core of this article. Described the coupling relationship in front of each classification, this part will be in the appropriate use of and to be clear, I’ll try to explain in each scheme of this scheme coupling, but some solutions to realize there is no standard, its most important is to bring the idea to solve the problem, how would it specific coupling other roles, It is the tradeoff of the implementation as the developer understands it. For the time being, each scheme will be listed first, and then each scheme will be elaborated respectively.
- Direct call
- delegate
- proxy
- block
- kvo & notification
- target-action
- responder chain
3. Specific plan of process design
3.1 Direct Invocation
-
describe
Direct call transfer process is the most common, exists in any location of the project, in accord with this solution scenario, the sender to the receiver with good understanding, it also can be directly coupled to the receiver, but as I said, the plan itself there is no problem, just need developers to consider its applicability.
3.2 the delegate
-
describe
In iOS development, delegate is often translated as proxy, and we won’t discuss the correctness of this translation here, since there will be conflicts with proxy in our discussion, we will use the expression “delegate” in a more appropriate sense.
In real life, delegation usually means that one person cannot complete something and needs to entrust it to another person to help complete it. The same is true in the programming world: object A, unable to do what it needs to do, sends the event as A sender to object B, the receiver, to do it for it, and even returns the result. Role in this simple instructions, only the sender and the receiver, so also is relatively easy to understand, but in some situations, there may be two or more characters, this time to understanding the delegate may produce some problems, we will be in the back, after finished the proxy plan to again when comparing the two scheme in this paper. Delegate also implies that the sender has to promise to send events to the receiver: IF I ask you to do something, I have to do it myself, and you can’t just do it without me asking you and you don’t know what I’m doing.
-
coupling
The dependency of the sender on the receiver is optional. It can be directly dependent on the receiver or abstracted from the receiver. For example, the delegate object is injected through Protocol. The dependency of the receiver on the sender needs to be considered by the developer.
3.2 the proxy
-
describe
Proxy refers to using a double object instead of the actual object, for external access, in fact there are three roles in this scene, in addition to the sender and receiver, and a proxy, the sender was meant to want to visit the receiver, is actually visit agents, this design can control the access of the sender to the receiver.
-
coupling
Proxy applies to scenarios where there are three roles, where the sender can directly depend on the agent, and the agent can also directly depend on the receiver, but both interfaces can be decoupled by abstraction. Because of the variability of the design itself, the coupling is difficult to define.
-
Similarities and differences between proxy and delegate
Proxies and delegates personally find considerable similarity, and even in some scenarios, solutions that fit both definitions. We will elaborate on the same and different points:
-
The same
Speaking of similarities, the first is, of course, the topic that they illustrate as the main point of this article, namely event passing. More like this:
- Delegate: Can’t do it yourself and needs help
- The part of a proxy that sends events back to a receiver that it cannot do itself and needs assistance from others (in certain cases, more on the differences later)
This looks almost exactly the same in this particular case, so it brings up something I didn’t mention in the delegate section earlier. A good example of this would be the model of the adapter pattern: converting the interface of one class into another interface that the customer expects. Adapters allow classes with incompatible interfaces to work together.
Adapter mode
In this model, the Adapter can be thought of as the Adaptee’s proxy for external access, and the Adapter passes events to
The behavior of Adaptee can be considered a delegate, or even the first direct call (because Adapter can rely on Adaptee directly). So how do you understand such a scene in accordance with the characteristics of multiple solutions, write here I want to be clear, this paper describes all of the plan, doesn’t mean it to adapt to the scenario were independent of each other, under complex scene, its already can be used as a whole and part of the different point of view, it is also important in the case of OO design principles, And these programmes themselves are independent because of their different starting points.
-
different
Now, the difference between a proxy and a delegate, first of all, is that they are semantically completely different. The similarities above are only the parts of a proxy that are similar to a delegate in a particular scenario, as we’ve already pointed out. So what does the part of the proxy that sends back events to the receiver look like in the non-specific case? There are no strict requirements for the interaction between the proxy and the receiver. In addition to the delega-like invocation mentioned above, the two parties can not understand each other. For example, they can be decouple through the observer mode, and even the proxy can directly return the received events without any processing.
-
3.3 block
-
describe
A block is an implementation of a closure in an OC. The closure itself is not event passing, which is the result of function Pointers passed as method parameters in the closure. We will not discuss the original design intent and other adaptation scenarios of closures themselves, but only those related to event passing. The online debate over the use of blocks and delegates has been going on for years. Here’s my point: The events that block hosts are almost identical to the scenes that delegate is used for, but block features allow it to be used for more detailed scenarios:
-
The event receiver needs to capture the context of the scope
The benefit of being able to capture context in this scenario is to reduce redundant parameter passing.
-
A one-time callback
Projects can often encounter some callback scenario, such as a bullet box, click the Settings if you don’t use Block and use other ways, such as the Delegate, the code will be scattered in different scope, thus it leads to lose cohesion, and in dealing with a click, which bounced is also need to deal with specific examples of callback, Third, because the scene itself is designed as a one-time frame, and because of the need to identify instances in the callback method, it leads to the need to explicitly hold the reference to the frame, which is contrary to the code style of one-time callback. The nature of blocks makes the callback handling of this scenario more cohesive, clear, and intuitive.
-
-
coupling
The coupling of the sender to the receiver is established in an abstract type, block, similar to a delegate.
3.4 kvo & notification
-
describe
The two approaches are put together because both KVO and Notification are implementations of the Observer pattern in the Apple Foundation framework. The essence of observer mode is a kind of middle-level design that can decouple both sides of the interaction. On this basis, refined design has adaptability to different scenarios.
Kvo is an observer mode for key changes, and the event sent by the sender is a key change.
Notification is more general and classifies events using notification names based on the observer pattern.
-
coupling
Observer mode decouples both sides of the interaction bidirectionally. Most refined observer modes can decouple both sides of the interaction bidirectionally at compile time, but may introduce problems that cannot be checked at compile time and only occur at run time. For example, kVO’s keypath, Notification’s notificaton.name, params.key and params.value.class all bring maintenance problems. I think such problems are due to compatibility in the design of such frameworks, so in practical use, Dependency issues can arise for such conventions, but you can also design a similar mechanism yourself, but generally only for your own project.
3.5 the target – the action
-
describe
Target-action is a scheme whose expressed purpose is how to perform an action on a target object, as its name implies. This design generally requires the language to be reflective, and the action needs to be responded to by the target object, which is very much like a special delegate from an abstract point of view, regardless of the original design and actual implementation: In a typical delegate design, constraints are placed on the receiver to ensure that the receiver can respond to the specified method, while target-action moves the constraints on the receiver away from the sender or interface, leaving the mediator or receiver to guarantee that the method can respond. Of course, this also creates a security problem, because this guarantee cannot be checked at compile time, as was the case with kVO and Notification.
-
coupling
Target-action, like the observer pattern, is bidirectional decoupled from both sides of the interaction and has the same problems that kVO/Notification can have when running.
3.5 responder chain
-
describe
Resonder Chain is an event transmission mechanism formed by means of responder chain, which is essentially an application of responsibility chain model. When the View hierarchy is too deep and events need to be transferred to distant objects in the same responser chain, the common delegate and block methods are difficult to solve this problem, or the solution can bring a lot of work, reponder Chain solution is very suitable.
-
coupling
The responder chain in Apple’s UIKit framework provides the basic support for such a scheme. The other thing you need to do is create a framework for event distribution, and there are many examples on the web. The sender and receiver do not have direct dependencies during transmission, they only have dependencies on the framework and responder chain. However, if the framework can provide event differentiation and parameter delivery mechanisms that are often similar to the design of Notification, the same maintenance issues can arise.
4. Advice given
This paper describes the process of event passing from the perspective of coupling relationship and process design, and in describing each process design, for its applicable scenarios and some controversial points are explained, so I hope you can clearly distinguish the way to use in the development. But for project development, knowing how to take advantage of the solutions provided by the platform is not enough. There are two problems:
- The solutions provided by the platform are not perfect for your project. In complex scenarios, or when you need to do some basic design for the architecture or some special situations, you need to make use of your accumulated knowledge and the capabilities provided by the platform to make customized designs that meet your requirements.
- Many projects for events did not make the rules, the use which way leads to agent/block/notification, and some of the scenes may is fit for multiple ways, so try to project for you to make the event passed rules governing, one can improve the developer itself to the design thinking, find rules when there is a problem, We can discuss and think together to come up with a more reasonable design; Second, it can improve the readability and maintainability of the project code. Everyone has the same way of development in this respect. Whether it is code review or work handover, it can put thinking on the practical logic and improve certain efficiency.
5. Conclusion
Thanks for reading!
The original address: www.notion.so/nakahira/iO…