1. Discover the problem
We all know that NSTimer uses target-action method. Usually target is the class itself. For convenience, we declare NSTimer as attribute variables, which will inevitably cause circular references (when you need to repeatedly execute timing tasks, if it is a single task, it will not cause circular references).
For example:
_timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
To understand in depth, the class has a member variable _timer, and the target set to the _timer is the class itself. In this way, the class retains _timer, and _timer retains this class, which will cause the problem of circular reference, which will eventually lead to the class being unable to be released correctly.
You may think that solving this problem is very simple. Release NSTimer at the right time. Most people will choose viewWillDisappear, viewDidDisappear, and dealloc. Of course, if you choose to release the NSTimer in the dealloc and think it is OK, you do not understand the execution time of the dealloc. Under popular science, the execution time of the dealloc is executed after self-release. In this way, dealloc is excluded, then you can only choose viewWillDisappear and viewDidDisappear (both push and pop are executed). But these two methods often fail to meet the needs.
2. Solve the problem
If you have learned about NSTimer circular references, you know that there are two common methods to solve:
- Use block encapsulation, target is set to NSTimer itself
- Since it is because the target is caused by self itself, then set the target as another object
(Not to mention the first block, everyone also likes this method, but sometimes they don’t want to use block. They want to use the second method, but there are many inconveniences when using it. Target is other objects, and the action must also be in other objects. This is inconvenient to access the relevant information of self in action. So a third method was born.)
3. Use an object A with weak attribute to wrap self as target, and then forward A message. Accessing A is equivalent to accessing self, which perfectly solves the circular reference and retains the target-action method.
What you are more curious about is how to implement the class A with weak attribute. Let’s take a look at the code below:
#import <Foundation/> #pragma mark - #pragma mark - Built-in weak object (can be used to classify weak attributes)@interface XWWeakObject : NSObject @property (nullable, nonatomic, weak, readonly) id weakObject; - (instancetype _Nullable )initWeakObject:(id _Nullable )obj; + (instancetype _Nullable )proxyWeakObject:(id _Nullable )obj; @end #import "" @implementation XWWeakObject -(instancetype)initWeakObject:(id)obj{ _weakObject = obj; return self; } +(instancetype)proxyWeakObject:(id)obj{ return [[XWWeakObject alloc] initWeakObject:obj]; } - (id)forwardingTargetForSelector:(SEL)selector { return _weakObject; } - (void)forwardInvocation:(NSInvocation *)invocation { void *null = NULL; [invocation setReturnValue:&null]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { return [NSObject instanceMethodSignatureForSelector:@selector(init)]; } - (BOOL)respondsToSelector:(SEL)aSelector { return [_weakObject respondsToSelector:aSelector]; } - (BOOL)isEqual:(id)object { return [_weakObject isEqual:object]; } - (NSUInteger)hash { return [_weakObject hash]; } - (Class)superclass { return [_weakObject superclass]; } - (Class)class { return [_weakObject class]; } - (BOOL)isKindOfClass:(Class)aClass { return [_weakObject isKindOfClass:aClass]; } - (BOOL)isMemberOfClass:(Class)aClass { return [_weakObject isMemberOfClass:aClass]; } - (BOOL)conformsToProtocol:(Protocol *)aProtocol { return [_weakObject conformsToProtocol:aProtocol]; } - (BOOL)isProxy { return YES; } - (NSString *)description { return [_weakObject description]; } - (NSString *)debugDescription { return [_weakObject debugDescription]; } @end
The XWWeakObject class has a weak read-only weakObject object (this class can also be used to declare weak attributes in categories: the classification itself cannot declare weak attributes).
The object of this class is forwarded and forwarded at runtime. When accessing the XWWeakObject object, it is equivalent to accessing its attribute weakObject object.
Finally, let’s see how to implement it using code:
- (void)viewDidLoad { [super viewDidLoad]; XWWeakObject *target = [XWWeakObject proxyWeakObject:self]; = [NSTimer scheduledTimerWithTimeInterval:1 target:target selector:@selector(timerCount) userInfo:nil repeats:YES]; } -(void)timerCount{ } -(void)dealloc{ [_timer invalidate]; _timer = nil; }
The premise is a property of self. Create an XWWeakObject object target. The target is the internal weak attribute pointing to self. It is equivalent to the target owning self and weak. The retain of self does not add 1. The timer owns the XWWeakObject object target, the retain of target adds 1. The direct relationship between timer and self is that timer is only a property of self, so it seems that no circular reference is formed.
Three written at the end
Although this method is not as easy as block, it is still a good method and a way to save the system. Those who like to use target-action or are not familiar with block can learn it. And XWWeakObject can do more than this. XWWeakObject can solve many similar circular reference problems, solve classification definition weak attributes, etc.
Some people may have questions about why the same target-action button does not have circular references. Students who have studied should know that the weak operation is done in UIControl, that is, when it is really held, it does not cause the retain to add 1, and the NSTimer does not do weak operation due to runloop.
Gossip
The above content only represents personal ideas. If you have better ideas and better solutions, you can discuss them together.
Summarize
The above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.