Last blog after we talked about signalproducer The basic implementation of the struct body, we'll talk about signalproducerprotocol Start and Lift series methods . The method extension of the Signalproducer struct is the same as the signal extension, are protocol-oriented extensions . First, a SIGNALPRODUCERPROTOCOL protocol is created so that signalproducer in the extension follows the Span style= "COLOR: #ff0000" > signalproducerprotocol protocol. Then we extend to Signalproducerprotocol . In this way, signalproducer struct has our Signalproducerprotocol The method extended in the protocol. This is also what we said earlier about "protocol-oriented expansion."
Let's talk about it today. The start and lift series methods in the signalproducerprotocol protocol extension. Both the start series method and the lift series approach are built on the basis of the signalproducer startwithsignal (Setup) core approach. As for the implementation of the Startwithsignal (Setup) method , the previous blog gives the corresponding introduction and gives the use of the core method, in this do not do too much to repeat.
In the signalproducerprotocol protocol extension, the method is basically the encapsulation of the B method, but the use of scene and function more specificity, more convenient usage. Let's take a look at the start and lift series methods of the Signalproducerprotocol protocol extension.
First, Start series method
The primary function of the start series method in the signalproducerprotocol protocol extension is to add the observer to the signal bag in Signalproducer, which is associated with Signal's The Observer () series method is similar. Below is part of the start series method, in the following method, the core is the Start (Observer) method. The parameter of the method is an object of the observer, and the start (Observer) method is responsible for adding the observer to the signal bag in the signalproducer . The following sequence of start methods is called the Start (Observer) method.
Because the start series method is very similar, here do not enumerate, below is part of the Start method, the rest of the ellipsis and the code below the implementation principle of the same, do not do too much to repeat.
After reading the start series method implementation, we look at the Start series method use. Below is a partial use case of the Start series method, which is described below:
-
First, a producer object is created from
the Signalproducer init (value) constructor, which is reserved.
-
It then creates an observer,
Subscriber1, and gives the processing closure of the value event.
-
The
start (Observer) and Startwithsignal () methods are then called to add Subscriber1 to the semaphore.
-
Then call some of the column start () methods to add a new semaphore to the signal.
The console below is the output of the snippet instance, from the output we know that the primary function of the start () series method is to add the observer to the signal. After the Observer has finished adding, it calls the trailing closure of the Signalproducer constructor. The specific code is shown below.
Ii. advanced usage of closure types
Before we talk about lift, let's take a look at the example of closure type use. Because the implementation of the lift correlation method is more complex, it involves some advanced usage of the closure method type. Next we look at the advanced usage of the function type from the perspective of swift language, which is also used in lift, or it is necessary to carry out a separate chat. Below are some specific examples.
1. Create MyClass class
First we create a simple class MyClass, which is simpler, which is a property, a constructor, an Add method. The Add (Other) method is the protagonist of the MyClass we will use later. Because the code below is relatively simple here do not do too much to repeat. Next to MyClass is the MyClass class test case, as shown below.
2. Create Myclassproducer class
Next we create a Myclassproducer class that uses the MyClass class in the class. There is also an Add method in Myclassproducer, except that the Add method receives a closure parameter, and the return value is a MyClass type. The parameter type for add () is (MyClass) , ( MyClass), MyClass. The closure type receives a parameter of type MyClass, and then returns a (MyClass)-MyClass type of closure. The parameters of the MyClass type, (MyClass) , are another MyClass type, and the return value is MyClass.
The closure closure is executed directly in the Add (closure) method and returns the object of the MyClass type that the closure eventually returns. The specific code is shown below.
3. Unconventional usage of Myclassproducer class
Let's take a look at the direct use of the Add (closure) method in the Myclassproducer class. Of course, under normal circumstances, the above-mentioned wording is particularly cumbersome, but the use of the way is also more troublesome. Let's take a look at the code that calls the Add (closure) method directly.
-
First we create an object myProducer1 of type Myclassproducer.
-
Then call MyProducer1 's Add (closure) method directly. The parameter of the trailing closure of add () is an object of type MyClass MyClass1, whose return value is (MyClass) a closure of the->myclass type, so we return a closure block directly in the trailing block, and the type of the returned closure block is
( MyClass)->myclass. Then an object of type MyClass is returned in the (MyClass)->myclass type of closure block, and when the object is created, the parameters MyClass1 and Myclass2 of the two closures are used.
-
Then we print the Des property of the Sum01 object, which is the closure of the two parameters of the closure packet. The specific results are shown below.
4. General usage of the Add method in the Myclassproducer class
The use of the Add (closure) method in the previous section is non-conventional, because it is obscure to use the Add (closure) method directly, and closure nested closures, the form of closures is really confusing. It can be said that direct use has no advantage. Next, let's look at the general use of Add (closure).
The code snippet below is the general use of Add (closure) over and over again. From the snippet below we can see directly that add (closure) is not receiving a closure, but the type of Myclass.add (other:). In fact, Myclass.add (other:) This type corresponds to the method body passed to the Add (closure) closure. That is, the type of the Add (other:) method is equivalent to the MyClass closure type (MyClass), (MyClass). Therefore, the method body of the Add (other:) method can be supplied to add (closure) as a parameter . In other words (MyClass)-(MyClass)-The MyClass type is equivalent to MyClass. Add ( MyClass),MyClass.
The advantage of this is that the data can be separated from the algorithm, and the Add (closure) parameter closure corresponds to what algorithm the Add (closure) executes. This is most vividly manifested in the lift series method in the Signalproducer class. We'll introduce you later.
Third, the core method of lift series realization
Now let's take a look at the code implementation of the lift series method in Signalproducer. Of course, because the lift series methods are more, below will give the lift series of methods in the core of the content, while the rest of the non-explanation is from these core methods to extend the method. Next, let's take a look at the code implementation of the lift series method from easy to difficult.
1, Lift<u, f> (transform) code implementation
This method is a relatively independent and core method in lift series. The code snippet below is the implementation of this method. The explanations are as follows:
-
The method is a generic method that can hold two generic
<u, f>. The method parameter is an escape closure transform, and the closure parameter is a semaphore of type
signal<value, error> , and the return value is type signal<u, f> Semaphore, that is, the function of the transform closure is responsible for converting Signal<value, error> types of semaphores through certain algorithms into signal<u, f> types of semaphores. The return value of the entire function is a signalproducer<u, f> type of semaphore producer.
-
Method Body, a new Signalproducer object is returned, and the startwithsignal () method of the original Signalproducer object is called in the trailing closure of the Signalproducer constructor. In the trailing closure of the startwithsignal () method, the semaphore signal of the original Signalproducer object is converted to a new semaphore by transform closure. The observer of the new Signalproducer object is added to the bag of the converted semaphore and becomes its observer. The specific code is shown below.
To take a closer look at how the above code is implemented and how it works, we also need to analyze it with examples. The code snippet below is an example of how to use the above method, as described below:
-
First, an object producer of type Signalproducer<int, noerror> is created. In the object's trailing closure, a value event is sent that has the value of the integer 8888.
-
A new object Liftproducer is then created through the lift method of the producer object. In the lift method of the trailing closure of the producer object inside the
signal<int, noerror> type of Signal semaphore through the semaphore map method to convert it to
signal<string, Noerror> type of semaphore, and returns. The implementation of the code below and the lift () method is easy to know because the Observer object in the Liftproducer object is added to the converted
signal<string, the noerror> type of semaphore as the Observer, So the type of Liftproducer object is signalproducer<string, noerror>.
-
The trailing closure of the
lift () method in the code below is the closure of the transform in the above function implementation. The signal parameter below is the parameter that transform passed in when it was called.
-
Next, we have created three observers of type
observer<string, noerror> , and then added these observers to the semaphore of the Liftproducer object. Then we'll see the observation message printed on the console.
Based on the code implementation of lift (transform) and the running results of the above example, we give the schematic below. The diagram below is the whole process of executing the above example, a picture that wins thousands of words. According to the example above should be at a glance. Here is not too much to repeat.
In the extension of the Signalproducer, the following methods are all implemented on the basis of the above lift (transform), in the final analysis of the use of signal in the corresponding method. The ways in which these methods work and how they operate are very similar to the diagram above. It's just a different way of generating the middle semaphore.
Each method in the code snippet below uses the shorthand form of a trailing closure when using the lift (transform) method. The signal parameter is the value of the trailing closure, and the new semaphore generated by calling its corresponding method is the return of the trailing packet. The details are as follows. Of course, the lower part of the use of lift (transform) method, the other similar to the below, do not do too much to repeat.
2, Liftright<u, F, V, g> (transform) code implementation
Before looking at the code implementation of the Liftright method, it is necessary to review the contents of the second part of this blog's advanced usage of closure types. Because the content in the second part of this blog and the use of examples help to understand how the Liftright method is used and the mode of operation.
The code snippet below is the concrete implementation of the Liftright method, we should note that the Liftright method is private type, that is, the method does not directly leak the user, the user can not directly call the method. Of course, now we need to look at the code implementation of the Liftright method, to give the corresponding use example, so we can change the private to public.
From the implementation of the code below, we can intuitively feel that the code implementation of the Liftright method is quite complex. The complexity of the liftright and the return value of the complex is more complex. First, let's take a look at the Liftright parameter. The parameter is a closure named transform, which is of type (Signal<value, error>) , f> (Signal<u, signal<v), G >, the closure type requires a signal<value, error> type parameter whose return value is a type (Signal<u, f>), Signal<v, G > closures.
From the closure type, and then in the Reference second section (MyClass), (MyClass) , the->myclass closure type, and the closure type with Myclass.add (MyClass)- the correspondence between the >myclass methods. It's easy to see (Signal<value, error>) , signal<v, Signal<u, f>), g> The type of closure is equivalent to signal<value, Error>.method (Signal<u, f>)->signal<v, the method of the g> type. In the Signal class there are many methods that conform to Signal<value, Error>.method (Signal<u, f>)->signal<v, g> type, such as combinelatest in signal, Withlatest, take (until:), skip (until:) and other methods, which means that the method body of these methods can be used as the closure of the transform closure, we will introduce later.
3, Liftright<u, F, V, g> (transform) call directly
In accordance with the usual rules, we first give the method of use of liftright, of course, here is the use of the Liftright method is non-conventional practice, because we are directly used. But it's better for us to understand the structure of Liftright's code and how it works.
The code snippet below is an example of a direct call to the Liftright method, which is described below:
-
First, we created an object producer of type
signalproducer<string, noerror>, using the usual method.
-
Then, based on the code implementation of the Liftright method, two type aliases were created. The
liftrightproducerclosuretype type is the Producer object Call Liftright method is the type of closure returned, Closurereturntype is the closure type returned by the closure of the parameters of the Liftright method.
-
Once the type is defined, it is time for the producer object to call the Liftright method. The
liftrightproducerclosure (signalproducer) below is the closure constant returned by the method. In the return closure of the Liftright, we will producer the corresponding semaphore signal of the object and
liftrightproducerclosure The signal volume in the Signalproducer object received by the closure is othersignal, and the Combinelatest method is called to merge, as follows.
-
It then creates a Strproducer object and binds it with a signal semaphore. Then execute
liftrightproducerclosure (strproducer), the closure returns a new Otherproducer object, The Startwithvalues () method is followed by the execution of Otherproducer. It then calls the Observer that strproducer the semaphore that is bound to send the value. The specific results are as follows:
For the above code execution process, or to a direct view of the graph. This diagram below is the execution of the above code. The execution procedure is one by one corresponding to the execution steps of the above code. Comparisons can be made based on the diagram below the running steps of the code. About the diagram below, do not do too much to repeat.
4, Liftright<u, F, V, g> (transform) general use mode
In the above section we call the liftright method directly, and then we'll look at the general usage of Liftright. The so-called conventional way of using is to use the method of the implemented method body as transform closure. There are signal.combinelatest (Signal)->signal methods in which the method types in the Signal are equivalent to the closure type of the transform. Next we will use the Combinelatest method body to replace the trailing closure of the Liftright method described above.
The red box below is what we replace, the other code does not change. After we found the replacement, the output was consistent with our previous results. The right way to use the Liftright method is to use the correct posture.
After reading the implementation of the above liftright and how to use it, let's take a look at how Signalproducer internally uses the Liftright method. Below casually find a liftright use way, extrapolate.
Comparison of Liftright method and Liftleft method
In the lift series method, the Liftright () method is the way the above code snippet is used. We will introduce you later. The above-mentioned technique is more convenient to use. Out Liftright method, there is also a liftleft () method. The implementation of the Liftleft () method is similar to the Liftright () method code implementation, except that the producer Startwithsignal () method is called in a different order. Next we'll look at the differences between the two.
The code snippet below is the code implementation of Liftright and the Liftleft method. By contrast, it is not difficult to see that the main difference between the two is that the otherproducer and self startwithsignal () methods are executed in different order. In the Liftright () method, the Otherproducer startwithsignal is executed first, and the Startwithsignal () of self is executed after the completion. And liftleft happens to be the opposite.
We take producer.liftright () (Otherproducer) as an example, this right refers to the otherproducer startwithsignal () method on the left to take the lead. and Producer.liftleft () (Otherproducer) refers to the left of the producer Startwithsignal () method is the first execution completed.
In order to feel more intuitively the difference between the above two methods, we give the example below. According to the output of the example below, the difference between liftright and Liftleft is straightforward. The following examples are described below:
-
First we create two
Signalproducer objects, one sends the 0,1,2 value, the other sends the values of a, B, and C.
-
Then let the Producer1 object call the Liftright method, use Liftrightproducerclosure to stage the returned closure, and producer2 the incoming closure. Then call Rightproducer's Startwithsignal method. Call the Lifeleft method in a similar step
Based on the output of the above code snippet, it is not difficult to see the right side of The Producer.liftright () (Otherproducer) Otherproducer's Startwithsignal () method was first executed. and Producer.liftleft () (Otherproducer) refers to the left of the producer Startwithsignal () method is the first execution completed.
Below is the Liftleft () method, which is used in the same way as the Liftright usage, as follows:
Many of the methods in Signalproducer are specific functions that are implemented on the basis of lift, liftright, or Liftleft methods. The future blog will be introduced on a continuous rolling. Because space is limited, today's blog is here first, next blog we will continue to parse the Reactiveswift framework of other content.
The above code GitHub share address:Https://github.com/lizelu/TipSwiftForRac
Reactiveswift source Parsing (ix) code implementation of the start and lift series methods in Signalproducerprotocol extension