Do you really know about iOS proxy design patterns?

Source: Internet
Author: User
Tags modifiers

How messages are delivered in the OS

There are many types of messaging in iOS, so here's a quick introduction to the various ways to deliver messages.

    • Notifications: Message reception and message broadcast in iOS by notification hubs is a one-to-many message delivery method.

    • Agent: is a universal design mode, the iOS in the support of the agent is very good, by the agent object, the delegate, the Protocol is composed of three parts.

    • A callback method introduced in block:ios4.0 that allows callback processing code to be written directly in block code blocks, looking logically clear and neatly coded.

    • Target action: The object method is called by passing the object to another class in another class as target, which is similar in memory terms to the proxy.

    • Kvo:nsobject's category-nskeyvalueobserving, which monitors the change of a value by means of a property listener, invokes the callback method of KVO when a change in values occurs.

..... Of course there are other callback methods, here is simply a list.

Basic use of agents

Proxy is a common design pattern, in iOS support for the proxy design pattern is very good, there is a specific syntax to implement the proxy mode, OC language can be implemented through the @protocol protocol.

The agent mainly consists of three parts:

    • Protocol: Used to specify what the agent can do and what must be done.

    • Agent: Complete the functions that the client needs to implement according to the specified protocol.

    • Delegate: Specifies what function the agent accomplishes according to the specified protocol.

Here is a picture to illustrate the relationship between the three parties:

The concept of the protocol-protocol

From which we can see the relationship between the three parties, in the actual application of the agreement to define the behavior of the agent, the content of the agreement is generally a list of methods, of course, you can also define attributes, I will in the next article in passing the agreement to define the properties.

A protocol is a public definition, and if it's just a class, what we often do is write it in a class. If multiple classes are using the same protocol, it is recommended to create a protocol file that defines the protocol in this file. The following protocols can be inherited, such as our common UITableView, because of the inheritance from Uiscrollview, so it will also inherit the uiscrollviewdelegate over, We can get state parameters such as UITableView offset by proxy method.

A protocol can only define a common set of interfaces, similar to the role of a binding agent. But cannot provide the concrete implementation method, the implementation method needs the proxy object to implement. The protocol can inherit other protocols, and multiple protocols can be inherited, and the object in iOS does not support multiple inheritance, and the protocol can inherit more.

// The current protocol inherits three protocols so that the list of methods in the other three protocols will be inherited . @protocol loginprotocol-(void) Userloginwithusername: (NSString *) Username password: (nsstring *) password; @end

The protocol has two modifiers @optional and @required, creating a protocol that, if not declared, is @required state by default. These two modifiers are just conventions that are mandatory to comply with the protocol, if the @required state of the method agent does not comply, will be reported a yellow warning, but only a binding role, no other functions.

Whether it is @optional or @required, the proxy method is called by the delegate to determine whether the agent implements the current method, or it can cause a crash.

Example:

// determines whether the proxy object implements this method, and no implementation can cause crashes if ([Self. Delegate respondstoselector: @selector (Userloginwithusername:password:)]) {    [self. Delegate userLoginWithUsername:self.username.text Password:self.password.text];}

Here we will use a small example to explain the problem:

Example: Suppose I was knocking on the code at the company, I was happy, suddenly thirsty, and wanted to drink a bottle of black tea. Then I can pick up the phone to the takeout app to set a black tea, and then the takeaway app will order to the store and let the store sent to me.

In this process, the takeaway app is my agent, I am the principal, I bought a bottle of black tea and paid the takeaway app money, this is the purchase agreement. I only need to buy from the takeaway app, the specific operations are handled by the takeaway app, I just need to finally receive this bottle of black tea can be. The money I pay is the parameter, the last black tea sent over is the result of processing.

But I buy black tea at the same time, I also want to eat Pizza Pizza Hut, I need to add to Pizza Hut app to order a meal, the above takeaway app does not have this function. I bought a pizza from Pizza Hut, Pizza Hut as my agent to make this pizza for me, and finally sent to my hands. This is the proxy object and I am the principal.

In iOS, a proxy can have multiple delegates, and a delegate can have multiple agents. I have designated the takeaway app and Pizza Hut two agents, you can also specify a number of agents such as McDonald's, the client can also serve multiple agents.

Proxy objects in many cases can actually be reused, you can create multiple proxy objects for multiple client services, below will be a small example to introduce the controller agent reuse.

The following is a simple proxy:

First define a protocol class to define the public protocol

#import @protocol loginprotocol@optional-(void) Userloginwithusername: (NSString *) Username password: (NSString * ) password; @end

Define the delegate class, here is a simple implementation of a user login function, the user login after the account password passed out, there is an agent to deal with specific login details.

#import #import "LoginProtocol.h"/** * The current class is a delegate class. After the user has logged in, let the proxy object implement the details of the login, the delegate class does not need to know the specifics of the implementation. */@interfaceLoginviewcontroller:uiviewcontroller//to set proxy objects by property@property (nonatomic, weak)ID Delegate;@endImplementation section:@implementationLoginviewcontroller- (void) Loginbuttonclick: (UIButton *) button {//determines whether the proxy object implements this method, and no implementation can cause crashes  if([Self.Delegaterespondstoselector: @selector (Userloginwithusername:password:)]) {      //Invoke Proxy Object login method, proxy object to implement login method[Self.DelegateUserLoginWithUsername:self.username.text Password:self.password.text]; }}

Agent, to implement the specific login process, the client does not need to know the implementation details.

/compliance with login agreements@interfaceViewcontroller ()@end @implementationViewcontroller- (void) viewdidload {[Super viewdidload]; Loginviewcontroller*LOGINVC =[[Loginviewcontroller alloc] init]; LOGINVC.Delegate=Self ; [Self.navigationcontroller PUSHVIEWCONTROLLER:LOGINVC animated:yes];} /** * Proxy for specific login details*/- (void) Userloginwithusername: (NSString *) Username password: (NSString *) Password {NSLog (@"username:%@, password:%@", username, password);}

Agent usage principle

Agent implementation Process

The essence of Proxy in iOS is the transfer and operation of proxy object memory, after we set the proxy object in the delegate class, we actually make a weak reference to the proxy object with a pointer of type ID. The delegate lets the agent perform the action, actually sending a message to the object that the ID type pointer points to in the delegate class, and the object that this ID type pointer points to is the proxy object.

From the above figure, we find that the Proxy property of the principal is essentially the proxy object itself, and the proxy property pointer is set to the proxy object, which is equivalent to the proxy object only calling its own method in the principal, which causes a crash if the method is not implemented. From the information on the crash, it can be seen that the agent did not implement the method in the protocol caused by the crash.

The protocol is only a syntax, is to declare the agent in the Proxy property can invoke the method declared in the Protocol, and the implementation of the method in the protocol is done by the agent, and the parties and the parties do not know whether the agent has completed, do not need to know how to complete.

Agent Memory Management

Why do we use weak to set proxy properties?

The pointers we define are __strong type by default, and the property is essentially a member variable and a set, get method, and a pointer of type strong will cause a strong reference, which will inevitably affect the life cycle of an object, which will form a circular reference.

, because the proxy object uses a strong reference pointer, the delegate that is created loginvc the object and becomes the proxy for the LOGINVC. This causes the LOGINVC delegate property to strongly reference the proxy object, causing a circular reference problem, and eventually two objects will not be freed properly.

We set the delegate property of the LOGINVC object to the weak reference property. This works for us when the proxy object life cycle is present, and if the proxy object is freed, neither the delegate nor the proxy object will be crash due to memory release.

However, there is still a problem, really do not collapse it?

The following two methods are weak reference proxy objects, but the first one does not cause a crash after the proxy object is freed, and the second causes a crash.

12 @property (nonatomic, weak) iddelegate;@property (nonatomic, assign) iddelegate;

Weak and assign are pointers to "non-owning relationships", and pointer variables decorated with these two modifiers do not alter the reference count of the referenced object. But after an object is freed, weak automatically points the pointer to nil, and assign does not. In iOS, sending a message to nil does not cause a crash, so assign causes a wild pointer error unrecognized selector sent to instance.

So if we decorate the agent property, or use weak to decorate it, it is more secure.

Controller Slimming-Proxy object

Why should I use a proxy object?

As the project becomes more complex, the controller becomes more and more bloated as the business grows. In this case, many people think of the most recent MVVM design pattern of fire. But this model learning curve is very difficult to master, for the new project can be used, for an already very complex large and medium-sized projects, it is not very good to move the framework of this layer of things.

In the project to use more than the control should have UITableView, and some pages tend to uitableview a lot of processing logic, which is causing the controller bloated a big reason. For this kind of problem, we can consider to the controller to thin body, through the proxy object way to the controller thin body.

What is a proxy object

It is usual for the controller to use UITableView (the ugly picture, mainly meaning understanding on the line)

This is our optimized controller composition.

As can be seen from the above two graphs, we will uitableview delegate and datasource separate out, by a proxy object class control, only the controller must handle the logic to pass to the controller processing.

UITableView's data processing, display logic and simple logical interaction are handled by the agent object, and the controller-related logic processing is passed out to the controller to deal with, so the controller's work is much less, and the coupling degree is greatly reduced. In this way, we only need to handle the work to be handled by the proxy object, and pass some parameters.

Here we use a piece of code to implement a simple proxy object

Declaration of the Proxy object. h file

void (^selectcell) (Nsindexpath *indexpath); /* * *   */ @interface  /* *  Create a proxy object instance and send a list of data to the  proxy object to pass the message out, is to pass the message through the block way  outside the * **/ + (Instancetype) createtableviewdelegatewithdatalist: (Nsarray *) dataList                                        selectblock: (Selectcell) Selectblock;

Implementation in the proxy object. m file

#import "TableViewDelegateObj.h" @interfacetableviewdelegateobj () @property (nonatomic, strong) Nsarray*dataList; @property (nonatomic, copy) Selectcell Selectblock;@end @implementationTableviewdelegateobj+ (Instancetype) createtableviewdelegatewithdatalist: (Nsarray *) dataList Selectblock: (Selectcell) Selectblock {return[[Selfclass] alloc] inittableviewdelegatewithdatalist:datalist selectblock: Selectblock];} -(Instancetype) Inittableviewdelegatewithdatalist: (Nsarray *) dataList Selectblock: (Selectcell) selectblock { self=[Super Init]; if(self) {self.datalist=dataList; Self.selectblock=Selectblock; }    returnSelf ;} -(UITableViewCell *) TableView: (UITableView *) TableView Cellforrowatindexpath: (Nsindexpath *) Indexpath {StaticNSString *identifier =@"Cell"; UITableViewCell*cell =[TableView Dequeuereusablecellwithidentifier:identifier]; if(!cell) {Cell=[[UITableViewCell alloc] Initwithstyle:uitableviewcellstyledefault reuseidentifier:identifier]; } Cell.textLabel.text=Self.datalist[indexpath.row]; returnCell;} -(Nsinteger) TableView: (UITableView *) TableView numberofrowsinsection: (nsinteger) Section {returnSelf.dataList.count;} - (void) TableView: (UITableView *) TableView Didselectrowatindexpath: (Nsindexpath *) Indexpath {[TableView deselectrowatindexpath:indexpath animated:no]; //Pass the Click event through blockSelf.selectblock (Indexpath);}@endthe call to the outside controller is very simple, and a few lines of code are done. 123456self.tabledelegate=[Tableviewdelegateobj createTableViewDelegateWithDataList:self.dataList Selectblock:^ (Nsindexpath *Indexpath) {NSLog (@"clicked%ld Row cell", (Long) (Indexpath.row);}]; Self.tableview.Delegate=Self.tabledelegate;self.tableview.datasource= Self.tabledelegate;

In the controller only need to create a proxy object class, and the UITableView delegate and DataSource are handed to the proxy object to handle, so that the proxy object becomes the proxy of the UITableView, the controller is bloated and the decoupling of UITableView is solved.

The above code simply implements the function of clicking the cell, and if there are other requirements, it can be processed in the proxy object. The advantage of using a proxy object class is that if multiple uitableview logic is the same or similar, the proxy object can be reused.

Informal agreements

Brief introduction

Prior to iOS2.0 before the introduction of @protocol formal agreement, the function of implementing the protocol is mainly by adding category to NSObject. This type of category, compared to the iOS2.0 introduced after the @protocol, is called the informal agreement.

As mentioned above, informal agreements generally exist in the form of NSObject category. Because it is a category for NSObject, all NSObject-based subclasses accept the defined informal protocol. For @protocol, the compiler checks for syntax errors at compile time, while informal protocols do not check for implementations.

There is no @protocol @optional and @required in the informal agreement, as in the case of @protocol, it is necessary to determine whether the method is implemented.

// since the category is used, self must be used to determine whether the method is implemented if ([Self respondstoselector: @selector (Userloginwithusername:password:)])} {    [self userloginwithusername: Self.username.text Password:self.password.text];}

Examples of informal protocols

A number of informal protocols were also used early in iOS, such as calayerdelegate, an implementation of the informal agreement, which is essentially category.

@interface NSObject (calayerdelegate)-(void) Displaylayer: (Calayer *) layer; -(void) Drawlayer: (Calayer *) layer Incontext: (cgcontextref) ctx; -(void) Layoutsublayersoflayer: (Calayer *) layer; ID) Actionforlayer: (Calayer *) layer Forkey: (NSString *)event; @end

Proxy and block selection

There are a lot of callback methods in iOS, and the proxy and block functions are much more similar, all of which are direct callbacks, which one should we use, or better?

In fact, the two kinds of message delivery way, no better, which is not good to say straight .... We should distinguish between what should be used and what is more appropriate! Below I will briefly introduce the choice of proxy and block in different situations:

    • Multiple messaging, you should use delegate. When there is more than one message passing, it is more appropriate to use the delegate to make it look clearer. Block is not very good, this time block is not easy to maintain, and looks very bloated, very awkward. For example, there are many agents in the uitableview of Uikit if they are replaced by block implementations, we think of this scene in mind, here do not use code to write an example .... It simply seems unbearable.

    • The proxy property of a delegate object can have only one proxy object, and if you want the delegate object to invoke multiple proxy objects, the callback should use block.

The above figure in the proxy 1 can be set, Agent 2 and proxy 3 settings when the fork was crossed, because this step is the wrong operation. As we said above, delegate is just an address to save a proxy object, and if multiple proxies are set to be re-assigned, only the agent of the last setting will be truly assigned.

    • A singleton object is best not to use delegate. Singleton objects are always just the same object, and if you use delegate, it will cause us to say that the delegate property is being re-assigned, and eventually only one object can respond properly to the proxy method.

In this case we can use block way, in the main thread of multiple objects to use block is not a problem, below we will use a cyclic violence test block in the end there is no problem.

 nsoperationqueue *queue = [[Nsoperationqueue alloc] init]; Queue.maxconcurrentoperationcount  = 10   ; for  (int  i = 0 ; i < 100 ; I++ ^{[Logi            Nviewcontroller Shareinstance] Userloginwithsuccess:  ^ (nsstring *username) { NSLog ( @ " testtableviewcontroller:%d          

The above creates a new queue with Nsoperationqueue, sets the maximum number of concurrent numbers to 10, and then creates a 100-time loop. We can test a single case in the case of a block in a multi-threaded situation, the answer is OK. But we still need to pay attention to, in the multi-threaded case because it is a singleton object, we have to lock the necessary places in the block, to prevent the problem of resource looting occurs.

    • The proxy is optional, and block can only pass a parameter in the method call by passing a nil in, but this is not a big problem, no code cleanliness can be ignored.

[Self downloadtaskwithresumedata:resumedata                  sessionmanager:manager                        savepath:savepath                   progressBlock: Nil                    successblock:successblock                    Failureblock:failureblock];
    • The proxy is more faceted, and the block is more results-oriented. From the point of view of design mode, the agent is better oriented and the block is better oriented towards the result. For example, we use the Nsxmlparserdelegate proxy for XML parsing, there are many proxy methods in Nsxmlparserdelegate, Nsxmlparser will call these methods without interruption to pass some of the parameters of the transformation, This is the Nsxmlparser parsing process, which is more appropriate to show through proxies. For example, a network request comes back, it is better to show it by success, failure code block.

    • Performance, the performance of the block is slightly larger than delegate, because the block will involve the stack area to the heap copy operations, time and space consumption is greater than the agent. Instead, the agent simply defines a list of methods, adds a node to the objc_protocol_list that adheres to the Protocol object, and sends a message to the object that adheres to the protocol at run time. This article is not about block, so do not narrate it too much. Tang Qiao has an article about block, highly recommend this article to learn more about block.

Do you really know about iOS proxy design patterns?

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.