1 Introduction
In the "Blockskit Source Analysis (a)" We analyzed the Blockskit source code organization structure and the first part of the core source code. Here we go on to analyze the second part of Blockskit--dynamicdelegate (dynamic agent). The so-called dynamic agent, it sounds quite iffy. The actual word is the means of turning delegate into block.
2 Dynamic Proxy Example
Let's start with an example of how dynamic proxies are used:
- (ibaction) Annoyuser {//Create an alert viewUialertview *alertview = [[Uialertview alloc] initwithtitle:@"Hello world!"message:@"This alert ' s delegate is implemented using blocks. that's so cool! "DelegateNilcancelbuttontitle:@"Meh."otherbuttontitles:@"Woo!",Nil];//Gets the dynamic proxy object for the alert view (what is the dynamic proxy object will say later)A2dynamicdelegate *DD = Alertview. Bk_dynamicdelegate;//Call Dynamic proxy Object-(void) Implementmethod: (SEL) selector Withblock: (ID) block; method to allow SEL to map a block object (assuming called block1)[DD Implementmethod:@selector(Alertviewshouldenablefirstotherbutton:) withblock:^ (Uialertview *alertview) {NSLog(@"Message:%@", Alertview. Message);return YES; }];///ditto, allow the SEL to map-alertview:willdismisswithbuttonindex: to another block object (assuming called Block2)[DD Implementmethod:@selector(Alertview:willdismisswithbuttonindex:) withblock:^ (Uialertview *alertview,NsintegerButtonindex) {NSLog(@"You pushed button #%d (%@)", Buttonindex, [Alertview Buttontitleatindex:buttonindex]); }];//Set Alertview's delegate to dynamic proxyAlertview. Delegate= DD; [Alertview show]; }//Then, Alert view receives the Alertviewshouldenablefirstotherbutton when it is displayed: Message call Block1;alert View receives Alertview when it disappears: Willdismisswithbuttonindex: Message, call Block2
From the above code we can intuitively see: DD (Dynamic proxy object) is directly set to the delegate object of Alert view, then the alert view of the Uialertviewdelegate message is passed directly to the DD. DD then somehow turns the corresponding SEL call into the corresponding block call. We can also make the following guesses:
1. There may be a dic-like data structure within DD, key may be the block that Sel,value may be corresponding to, through Implementmethod:withblock: This method establishes the DIC mapping in the form of key-value pairs for SEL and block
2. The host object (in this case, Alertview) sends a delegate message to DD by passing the SEL,DD in the internal DIC data structure to find the corresponding block, which is found after the block is called.
The basic idea is this, but there are two issues that need to be addressed:
1. How is dd (Dynamic proxy object) created?
2. If a variety of delegate such as Uialertviewdelegate have different messages, any message can be sent to dd,dd how to accept arbitrary messages, it is clear that each message is not realistic.
3 message forwarding mechanism
Let's start by answering the second question: How dynamic agents can accept arbitrary messages.
When an object receives a message that it does not implement, the following conditions usually occur.
1. First look at whether the selector has been provided with a dynamic method resolution mechanism, and if provided, go to 2; if not provided, go to 3;
2. If the dynamic method resolution really provides the implementation for the selector, then call the implementation, complete the message delivery process, message forwarding will not be carried out, if not provided, then go to 3;
3. Next see whether the selector provides a message forwarding mechanism, if the message is provided for message forwarding, at this time, regardless of how the message forwarding is implemented, the program will not be crash. (Because the control of a message call is handled entirely by the message forwarding mechanism, even if the message is forwarded without doing anything, there will be no error in the compiler, and there will be no error prompting.) ); If no message forwarding mechanism is provided, go to 4;
4. Operation Error: Unrecognized selector, program crash;
We can tell by the above description. DD (A2dynamicdelegate Class) supports any message sending, not using message resolution or message forwarding. Actually through the code we can see that a2dynamicdelegate is inherited from the Nsproxy class, which is specifically for message forwarding. Classes that inherit from this class must implement the-(void) Forwardinvocation: (Nsinvocation *) Outerinv method. This is because the method is called when the object of the class receives an unrecognized message. So the DD message map process is like this: when DD receives an unrecognized message, it calls Forwardinvocation, and the parameter of the function OUTERINV the sel of the corresponding message, and then the SEL finds the corresponding block in the inside DIC. (A brief idea)
4 creation of dynamic proxy objects
A2dynamicdelegate How is this object created? Why do you see DD (a2dynamicdelegate) in the code as if it were a property of Alertview.
In fact, DD is implemented by NSObject (a2dynamicdelegate) classification. This classification associates the protocal and A2dynamicdelegate objects with the method of the associated object. So that the corresponding protocal have corresponding A2dynamicdelegate objects. The bk_dynamicdelegate of a class is actually looking for the protocal of the class corresponding to delegate, and then finds the corresponding A2dynamicdelegate object based on this protocal. Create an association if the A2dynamicdelegate object cannot be found. such as Alertview.bk_dynamicdelegate; finds the object associated with the Alertview delegate Uialertviewdelegate Protocal, creates one if it is not found, and makes an association.
The relevant code is as follows:
//FILE:NSOBJECT+A2DYNAMICDELEGATE.M-(ID) Bk_dynamicdelegatewithclass: (Class) CLS Forprotocol: (Protocol *) protocol{/** * Storing the dynamicDelegate asAn associated object ofThe delegating * Object not only allows us toLater retrieve theDelegate, but it also * creates a strong relationship toTheDelegate. Since delegates is weak * References on the part ofThe delegating object, a dynamicDelegate* would is deallocated immediately after its declaring scope ends. * Therefore, this strong relationship is required toEnsure that *Delegate' s lifetime is at least asLong asThat ofThe delegating object. **/__block a2dynamicdelegate *dynamicdelegate; Dispatch_sync (A2_backgroundqueue (), ^{dynamicdelegate = Objc_getassociatedobject (self, (__bridge constvoid*) protocol);if(!dynamicdelegate) {dynamicdelegate = [[CLS alloc] initwithprotocol:protocol]; Objc_setassociatedobject (self, (__bridge constvoid*) protocol, dynamicdelegate, objc_association_retain_nonatomic); } });returnDynamicdelegate;}
5 Code Design
A2dynamicdelegate is a dynamic proxy class, Nsobject_a2dynamicdelegate is a nsobject classification used to create dynamic proxy objects. A2blockinvocation This class we haven't said before, it's a layer of block encapsulation. A2dynamicdelegate inside the dictionary data structure is not a pure block, but the A2blockinvocation object.
The related class diagram is as follows:
The related sequence diagram is as follows:
Blockskit Source Analysis (ii)