preface
stayOC
In, we often encounter something calledCircular reference, no doubt,Circular referenceIt will lead to memory leakage. In severe cases, it is also possible to lead to application crash. We often encounterCircular referencenamelyBlock
(ordelegate
)Caused by, and the way to solve it is also the use of platitudesweak
To weakly reference the referenced object and break the loop, so as to avoid the problem of circular reference.
However, if you are a little careless, sometimes use itweak
It will also lead to the collapse of the application, resulting in irreparable consequences. This article is a brief description of how to use it correctlyweak
And sometimes it needs to be combinedstrong
To avoidCircular referenceMemory leak.
Block circular reference
One object holds oneBlock
, thisBlock
This object is referenced again in. This isCircular reference。 The most common and simplest is to hold the currentself
, which is often encountered in development. staySecondViewController.m
For example:
#import "SecondViewController.h"
#import "MyObject.h"
@interface SecondViewController ()
@property (nonatomic, strong) MyObject *obj;
@property (nonatomic, copy) NSString *name;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Second VC";
self.name = @"Alice";
self.obj = [[MyObject alloc] init];
[self.obj start:^{
NSLog(@"name: %@", self.name);
}];
}
- (void)dealloc
{
NSLog(@"OOPS! ⚠️⚠️⚠️ %s", __PRETTY_FUNCTION__);
}
@end
stayMyObject.h
in
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^ExecuteBlock)(void);
@interface MyObject : NSObject
- (void)start:(ExecuteBlock)block;
@end
NS_ASSUME_NONNULL_END
MyObject.m
in
#import "MyObject.h"
@interface MyObject()
@property (nonatomic, copy) ExecuteBlock myBlock;
@end
@implementation MyObject
- (instancetype)init
{
self = [super init];
if (self) {
[self initData];
}
return self;
}
- (void)initData
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.myBlock) {
self.myBlock();
}
});
}
- (void)start:(ExecuteBlock)block
{
self.myBlock = block;
}
@end
obviously,self
holdobj
,obj
holdblock
(start
Method parametersblock
), block
Hold againself
(name
Is currentself
A property of), thus causing obvious problemsCircular reference。
This kind of treatment is also very simple, aweak
You can do it:
self.obj = [[MyObject alloc] init];
__weak typeof(self) weakSelf = self;
[self.obj start:^{
NSLog(@"name: %@", weakSelf.name);
}];
Is there any problem with our handling here? The answer isNo problem。
Then we putname
change intoMember variable
, i.e.:
@interface SecondViewController ()
{
NSString *name;
}
@property (nonatomic, strong) MyObject *obj;
@end
......
self.obj = [[MyObject alloc] init];
__weak typeof(self) weakSelf = self;
[self.obj start:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"name: %@", strongSelf->name);
}];
......
Note that due toname
yesMember variable, cannot be usedweakSelf
To quotename
Because it’s aWeak pointer。 Therefore, we must be right hereweakSelf
Make a strong reference, that is, usestrongSelf
To quotename
。
Think about it, when the user enters the page, in10s
Return to the previous page in, and waitblock
What happens when it is executed?Application crash!!!
Crash analysis
Strange! Why does this problem happen? It feels like there’s no problem. Use itweakSelf
Avoid circular references and usestrongSelf
To refer to member variables, how can it collapse? Whenname
When it is an attribute, that isweakSelf.name
There will be no problem, justname
fromattributebecomeMember variableNot anymore?
In fact, as long as you understandOC
Mediummessage sendingMechanism, you can basically know the reason for the collapse mentioned above. stayOC
Yes, yesnil
Send message yes“Legal”Therefore, when usedPoint grammarWhen you come to visit, you actually visitattribute(here is)name
)YesgetterMethod, so there will be no collapse.
However, if it is acquisitionMember variableIf so, it is not a method, but throughThe self pointer directly accesses the memory address of its internal member variableAt this point, when the page has been released,self
No longer exists,strongSelf
meannil
, it is conceivable that for a non-existent“Object”, visit the so-called“Member variable”, i.enil -> name
, it’s no surprise that we’re going to collapse.
Crash resolution
I. try to use attributes
This approach is essentially based onOC
Message mechanism, rightnil
Sending messages is allowed. So evenself
If it is destroyed, there will be no problem because you passstrongSelf.name
The method is called,OC
Your messaging mechanism allows you to do this. Although sometimes we use it directly for performance reasonsMember variableBecause there is a price for calling methods, but in most cases, the performance considerations brought by this are acceptable and can be ignored.
Therefore, to be absolutely safe, inblock
Internal useattributeIt is a feasible and effective way to obtain.
Second, member variables are still usedweakSelf
Do a safety check
If you say I just want to useMember variable
It’s understandable to make the performance reach the optimal solution. This is also a necessary idea in our development. However, you should be careful enough to avoid collapse. The solution is rightweakSelf
Conduct safety inspection, such as:
self.obj = [[MyObject alloc] init];
__weak typeof(self) weakSelf = self;
[self.obj start:^{
if (!weakSelf) return; // Security-check here.
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"name: %@", strongSelf->name);
}];
summary
In development, we must avoidCircular reference、agentMemory leak caused by(memory leak
)Of course, I believe that for most developers, this basically does not need to think. They can be used to writing corresponding keywords or the middle tier to avoid this problem, but it is estimated that many people will appear in this articlecareless, leading to the problem of online rout.weak
Not at allblock
All situations need to be used, such as the animation provided by the systemAPI
:
[UIView animateWithDuration:1.0 animations:^{
NSLog(@"name: %@", self->name);
}];
Excessive unnecessaryweak
Using will make the code redundant and cause unnecessary performance problems!
Personal blog
Demo address
2021-03-18