[IOS learning basics] weak and strong, lazy loading, cyclic reference, and iosweak
I. weak and strong
1. Understanding
When I first started to learn the UI, the description of weak and strong was most often described as "introduced by ARC. weak is equivalent to assign in OC, but weak is used to modify objects, however, they do not add 1 to the reference count, while strong is equivalent to the retain specified in OC, which will add 1 to the reference count ".
Principle of ARC: as long as there is another variable pointing to the object, the object will remain in the memory. When the pointer points to a new value or the pointer no longer exists, the associated object is automatically released. This rule applies to instance variables, synthesize attributes, and local variables.
The strong pointer can keep the object's life. If an object has a strong pointer pointing to it, it will not be released. On the contrary, if no strong pointer points to it, it will be released automatically. By default, all instance variables and local variables are Stong pointers.
Weak pointer variables can still point to an object, but do not belong to the owner of the object. That is, when the object is destroyed, the weak pointer automatically points to nil (NULL pointer ).
MARK Portal: MJ's analysis of weak and strong
2. weak and strong pointer usage notes
// We often see that all the attributes referenced from the xib controller are weak pointers. Why are those control objects not automatically released?
@ Property (nonatomic, weak) IBOOutlet UIButton * btn;
// This reference relationship was formed when the control was originally created or placed in xib.
UIViewController-> UIView-> subView-> UIButton
// Enter the UIViewcontroller. h file and find
@ Property (null_resettable, nonatomic, strong) UIView * view; // This item is strongly referenced.
// Therefore, the reference relationship above is that xib is a strong reference to this button, and the attribute you declare is a weak reference to it.
@ Interface LZVC ()
@ Property (nonatomic, weak) UIView * myView; @ end @ implementation LZVC-(void) viewDidLoad {[super viewDidLoad];
// Warning: ("Warning: Assigning retained object to weak variable; object will be released after assignment ")
_myView = [[UIView alloc] initWithFrame:self.view.frame];
_myView.backgroundColor = [UIColor redColor];
[self.view addSubview:_myView];
} @ End// We will find that _ myView is not added to self at all. in view, because _ myView is a weak pointer and does not have the ability to hold objects, the member variable initialized after the equal sign is automatically released because no strong pointer is referenced after the initialization. Therefore, _ myView gets blank.
// Correction method:
// ① Change the weak in the member attribute declaration to strong. (Directly make _ myView strongly reference the initialized object, so that the initialized object will not be automatically released)
// ② Change the warning to the following:
// Because all instance variables and local variables are strong pointers by default, myView strongly references the initialized object, and then _ myView weakly references myView
UIView * myView = [[UIView alloc] initWithFrame: self. view. frame]; UIView * myView. backgroundColor = [UIColor redColor]; _ myView = myView; [self. view addSubview: _ myView];
3. Use Time of weak and strong (based on the above features, I will perform the following tests)
1> I created a new subclass TestView inherited from UIView, added a new property text, and overwritten its dealloc method. I want to see when TestView will be released.
@ Property (nonatomic, copy) NSString * text; // attribute
// Rewrite Dealloc and print the data-(void) dealloc {NSLog (@ "% @ ---- % s", self. text ,__ func __);}
2> In the controller, I wrote the following code:
# Import "LZVC. h "# import" TestView. h "@ interface LZVC () @ property (nonatomic, weak) TestView * myWeakView; // weak reference @ property (nonatomic, strong) TestView * myStongView; // strongly reference @ end @ implementation LZVC-(void) viewDidLoad {[super viewDidLoad]; self. view. backgroundColor = [UIColor whiteColor]; TestView * myWeakView = [[TestView alloc] initWithFrame: CGRectMake (0, 64,160,160)]; myWeakView. backgroundColor = [UIColor redColor]; myWeakView. text = @ "I'm a weak reference"; _ myWeakView = myWeakView; [self. view addSubview: _ myWeakView]; TestView * myStrongView = [[TestView alloc] initWithFrame: CGRectMake (160, 64,160,160)]; myStrongView. backgroundColor = [UIColor greenColor]; myStrongView. text = @ "I am strongly referenced"; _ myStongView = myStrongView; [self. view addSubview: _ myStongView] ;}# pragma mark click screen trigger-(void) touchesBegan :( NSSet <UITouch *> *) touches withEvent :( UIEvent *) event {if (self. myWeakView) {[self. myWeakView removeFromSuperview];} if (self. myStongView) {[self. myStongView removeFromSuperview];}
}
3> after clicking on the screen, both views are removed from the screen. The following figure shows that TestView with weak reference is released (because myWeakView is only strongly referenced by the Controller, the attributes you declare are strongly referenced)
4> I returned to the home page and destroyed the LZVC controller, printed and strongly referenced TestView (in addition to the strong reference of the controller, myStrongView,
5> conclusion: I believe you have learned from the printing in versions 3 and 4. If you want to release the lifecycle of a control as it is destroyed, use strong; if you only want it to be destroyed after it is removed, use weak
Ii. Lazy Loading
1. Lazy Loading
Lazy loading, also known as delayed loading, is loaded only when needed (low efficiency and low memory usage ). The so-called lazy loading is actually rewriting the getter method. To put it bluntly, it is to say that in development, when the resources need to be used in the program. Resources are not loaded when the program starts. These resources are loaded only when some resources are required for running.
We know that the memory of iOS devices is limited. If you load all the resources that will be used in the future at one time after the program starts, the memory of iOS devices may be exhausted. These resources include a large amount of data, images, audios, and so on. Therefore, when using lazy loading, we must first determine whether there are already available resources. If not, we need to instantiate them.
2. Benefits of lazy loading
1> do not write all the code for creating an object in the viewDidLoad method, making the code more readable.
2> the getter method of each control is responsible for instantiation. The code is highly independent and loosely coupled. Non-empty judgment is also performed to prevent repeated object loading.
3> only when resources are actually needed can we load them again, which saves memory resources, prevents objects from being created in advance, and prevents objects from being created before they are used (memory optimization, such as loading plist files and other memory-consuming operations ).
3. Use lazy loading to initialize member variables
@ Interface LZVC () @ property (nonatomic, strong) NSArray * dataSource; @ end @ implementation LZVC # pragma mark lazy loading-(NSArray *) dataSource {if (_ dataSource = nil) {_ dataSource = @ [@ "1", @ "2", @ "3", @ "4"];} return _ dataSource;} // use self. dataSource format
Here, by the way, we will talk about the member variables and attributes:
1> directly access the member variable: _ dataSource = @ [@ "5", @ "6"];
Direct assignment, intuitive and fast.
2> access member attributes: self. dataSource = @ [@ "5", @ "6"];
When values are assigned, the setter method is used. When values are obtained, the getter method is used. You can do something you want in the two methods (for example: the setter method controls the Data Validity and changes in the listening value, while the getter method's lazy loading shows its benefits.
Iii. circular reference (scenario)
1. Classic: proxy mode Delegate (UITableViewDelegate) Example
The view of the controller strongly references Tableview, while the delegate of tableview is the controller. If the following two proxy attributes are modified with strong, the circular reference problem will occur, the best way to solve this problem is to use weak for one of the two weak references ).
@property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
2. The NSTimer timer Target causes loop reference. NSTimer will hold the target object.
3. block is used as a member variable, and the block accesses self or its attributes to cause circular reference.