iOS內存優化之解決延遲釋放

    在實際開發過程中,使用NSTimer 或者 performSelector... afterdelay 在定時器事件未觸發的時候,如果返回上一個頁面,會由於runloop強持有target,短時間內不會釋放。造成內存不能及時釋放。而且等到定時器觸發事件時會執行已經沒有意義的邏輯運算,額外浪費資源。因此內存的及時釋放也是app內存優化的一個點。NSTimer的之前的博客已經實現,這裏就不多說了,這裏以以下代碼爲例。

@interface NSObject (JKBasicProvider)

- (void)jk_performSelector:(SEL)aSelector
                withObject:(nullable id)anArgument
                afterDelay:(NSTimeInterval)delay
                   inModes:(NSArray<NSRunLoopMode> *)modes;

- (void)jk_performBlock:(void(^)(void))block
             withObject:(id)anArgument
             afterDelay:(NSTimeInterval)delay
                inModes:(NSArray<NSRunLoopMode> *)modes;

- (void)jk_performSelector:(SEL)aSelector
                withObject:(nullable id)anArgument
                afterDelay:(NSTimeInterval)delay;

- (void)jk_performBlock:(void(^)(void))block
             withObject:(nullable id)anArgument
             afterDelay:(NSTimeInterval)delay;
@end
#import "NSObject+JKBasicProvider.h"

@interface JKPerformSelectorTarget : NSObject

@property (nonatomic, weak) id actionTarget;
@property (nonatomic, weak) id actionArgument;
@property (nonatomic, assign) SEL actionSelector;
@property (nonatomic, copy) void(^actionBlock)(void);

@end

@implementation JKPerformSelectorTarget

- (instancetype)initWithSelector:(SEL)selector
                          target:(id)target
                        argument:(nullable id)argument
{
    self = [super init];
    if (self) {
        self.actionSelector = selector;
        self.actionTarget = target;
        self.actionArgument = argument;
        self.actionBlock = nil;
    }
    return self;
}

- (instancetype)initWithBlock:(void(^)(void))actionBlock
                       target:(id)target
                     argument:(nullable id)argument
{
  self = [super init];
    if (self) {
        self.actionTarget = target;
        self.actionArgument = argument;
        self.actionBlock = nil;
    }
    return self;
}

- (void)performSelectorAction:(id)argument
{
    if (self.actionTarget) {
        if (self.actionBlock) {
            self.actionBlock();
        } else {
            IMP imp = [self.actionTarget methodForSelector:self.actionSelector];
            void (*func)(id, SEL,id) = (void *)imp;
            func(self.actionTarget, self.actionSelector,argument);
        }
    }
}

@end

@implementation NSObject (JKBasicProvider)

- (void)jk_performSelector:(SEL)aSelector
                withObject:(nullable id)anArgument
                afterDelay:(NSTimeInterval)delay
                   inModes:(NSArray<NSRunLoopMode> *)modes
{
    if (delay > 0) {
        JKPerformSelectorTarget *target = [[JKPerformSelectorTarget alloc] initWithSelector:aSelector target:self argument:anArgument];
        [target performSelector:@selector(performSelectorAction:) withObject:anArgument afterDelay:delay inModes:modes];
    } else {
        [self performSelector:aSelector withObject:anArgument afterDelay:delay inModes:modes];
    }
}

- (void)jk_performBlock:(void(^)(void))block
             withObject:(id)anArgument
             afterDelay:(NSTimeInterval)delay
                inModes:(NSArray<NSRunLoopMode> *)modes
{
    JKPerformSelectorTarget *target = [[JKPerformSelectorTarget alloc] initWithBlock:block target:self argument:anArgument];
     [target performSelector:@selector(performSelectorAction:) withObject:anArgument afterDelay:delay inModes:modes];
}

- (void)jk_performSelector:(SEL)aSelector
                withObject:(nullable id)anArgument
                afterDelay:(NSTimeInterval)delay
{
    if (delay > 0) {
       JKPerformSelectorTarget *target = [[JKPerformSelectorTarget alloc] initWithSelector:aSelector target:self argument:anArgument];
        [target performSelector:@selector(performSelectorAction:) withObject:anArgument afterDelay:delay];
    } else {
        [self performSelector:aSelector withObject:anArgument afterDelay:delay];
    }
}

- (void)jk_performBlock:(void(^)(void))block
             withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay
{
    JKPerformSelectorTarget *target = [[JKPerformSelectorTarget alloc] initWithBlock:block target:self argument:anArgument];
    [target performSelector:@selector(performSelectorAction:) withObject:anArgument afterDelay:delay];
}
@end

原理就是通過中介者,用一個較小內存對象替換較大內存內對象,讓較大內存對象能夠及時釋放同時在定時器響應的事件到來時,如果真正的target已經被銷燬了,那麼就不再執行對應的邏輯了。避免資源浪費,提高代碼健壯性。
更多技術乾貨文章可以掃描下方二維碼:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章