Turn from <简书 —="" 刘小壮="">
Basic use of agents
Proxy is a common design pattern, in which the iOS proxy design pattern is well supported, there is a specific syntax to implement the proxy mode, OC language can be @Protocol implemented by the 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 through the agreement to define the behavior of the agent, the content of the agreement is generally a list of methods, of course, can also define attributes.
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 protocols that follow can be inherited, for example, as we often UITableView do, because of inheritance, UIScrollView so UIScrollViewDelegate we will inherit from it, we can get the UITableView state parameters such as 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 can inherit multiple protocols, in which the iOS object does not support multiple inheritance, and the protocol can inherit more.
// 当前协议继承了三个协议,这样其他三个协议中的方法列表都会被继承过来@protocol LoginProtocol <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password;@end
The protocol has two modifiers @optional and @required creates a protocol if it is not declared, the default is @required state. These two modifiers are just conventions that enforce the need to obey the protocol, and if @required the state's method agent does not follow, it will report a yellow warning, just as a constraint, with no other functionality.
Whether @optional or not the @required proxy method is called by the delegate, it is necessary to judge whether the agent implements the current method, or it will cause a crash.
Example:
// 判断代理对象是否实现这个方法,没有实现会导致崩溃if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) { [self.delegate userLoginWithUsername:self.username.text password:self.password.text];}
Example
Suppose I was knocking on the code at the company, knocking happily, suddenly thirsty, want 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, you 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.
Realize
First define a protocol class to define the public protocol
#import <Foundation/Foundation.h>@protocol LoginProtocol <NSObject>@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 <UIKit/UIKit.h>#import "LoginProtocol.h"/** * 当前类是委托类。用户登录后,让代理对象去实现登录的具体细节,委托类不需要知道其中实现的具体细节。 */@interface LoginViewController : UIViewController// 通过属性来设置代理对象@property (nonatomic, weak) id<LoginProtocol> delegate;@end实现部分:@implementation LoginViewController- (void)loginButtonClick:(UIButton *)button { // 判断代理对象是否实现这个方法,没有实现会导致崩溃 if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) { // 调用代理对象的登录方法,代理对象去实现登录方法 [self.delegate userLoginWithUsername:self.username.text password:self.password.text]; }}
Agent, to implement the specific login process, the client does not need to know the implementation details.
// 遵守登录协议@interface ViewController () <LoginProtocol> @end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; LoginViewController *loginVC = [[LoginViewController alloc] init]; loginVC.delegate = self; [self.navigationController pushViewController:loginVC animated:YES];}/** * 代理方实现具体登录细节 */- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password { NSLog(@"username : %@, password : %@", username, password);}
Agent implementation process using principle agent
The iOS essence of agent in agent is the transfer and operation of proxy object memory.
After we set the proxy object in the delegate class, we actually id made a weak reference to the proxy object with a pointer of a type. The delegate lets the agent perform the action, actually sending a message to the object that the type pointer points to in the delegate class, id and the id object that the 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 typed by default, __strong and the property is essentially a member variable and set、get method, and a strong pointer of type will cause a strong reference, which will inevitably affect the life cycle of an object, and this will form a circular reference.
Strong references
, because the proxy object uses a strong reference pointer, it references the created delegate LoginVC object and becomes LoginVC the proxy. This causes LoginVC the property to delegate strongly reference the proxy object, causing a circular reference problem, and eventually two objects will not be freed properly.
Weak references
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.
Weak or assign?
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.
@property (nonatomic, weak) id<LoginProtocol> delegate;@property (nonatomic, assign) id<LoginProtocol> delegate;
weakAnd assign is a "non-owning relationship" pointer, a pointer variable decorated with these two modifiers does not alter the reference count of the referenced object. However, when an object is freed, weak will automatically point the pointer nil , but assign not. In iOS , sending a nil message does not cause a crash, so assign it 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 deal with a lot of logic, this is a big reason for the controller bloated. 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
This is the usual controller UITableView to use (the ugly picture, mainly the meaning of 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.
UITableViewThe data processing, display logic and simple logical interaction are handled by the agent object, and the logic processing of the controller 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.
IOS Proxy design mode