Weak & Strong

WeakSelf和StrongSelf傻傻分不清楚,记录一下

准备工作

SimulationRequest

  • SimulationRequest.h
@interface SimulationRequest : NSObject
@property (nonatomic, strong) NSMutableDictionary *requestDic;
+ (instancetype)sharkRequest;       //单例对象
+ (instancetype)request;            //init对象

- (NSUInteger)simulationRequestCompletation:(void(^)(NSString *msg))completion;

@end
  • SimulationRequest.m
static dispatch_queue_t _kqueue = nil;
static NSUInteger _idt = 0;
@implementation SimulationRequest

+ (instancetype)sharkRequest{
    static SimulationRequest *_kRequest = nil;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        _kRequest = [[SimulationRequest alloc] init];
    });
    return _kRequest;
}

- (instancetype)init{
    self = [super init];
    if (self) {
        self.requestDic = [[NSMutableDictionary alloc] init];
    }
    return self;
}

+ (void)initialize{
    if (_kqueue == nil) {
        _kqueue = dispatch_queue_create("SimulationRequest.queue", DISPATCH_QUEUE_SERIAL);
        dispatch_queue_set_specific(_kqueue, &_kqueue, &_kqueue, NULL);
    }
}

+ (instancetype)request{
    SimulationRequest *request = [[self alloc] init];
    return request;
}

- (NSUInteger)simulationRequestCompletation:(void (^)(NSString * _Nonnull))completion{
    
    // 这里其实是需要对idt进行加锁的,Demo中请求在主线程中进行,省略了加锁操作
    _idt ++;
    if (completion) {
        [self.requestDic setObject:[completion copy] forKey:@(_idt)];
    }
    dispatch_async(_kqueue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            void(^t)(NSString *) = [self.requestDic objectForKey:@(_idt)];
            if (t) {
                t(@"hello!!");
                [self.requestDic removeObjectForKey:@(_idt)];
            }
        });
    });
    return _idt;
}

@end

创建对象

  • WeakStrongClass.m
@implementation WeakStrongClass

- (void)request{
    [[SimulationRequest sharkRequest] simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!!");
        [self logMsg];
    }];
}

- (void)logMsg{
    NSLog(@"%p logMsg", &self);
}

- (void)dealloc{
    NSLog(@"%s", __func__);
}

@end

测试开始

测试一 单例Request

  • 创建一个WeakStrongClass类型局部变量进行网络请求
void weakStrongTest1(void) {
    WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
    [obj1 request];
}
  • 日志输出
 Hello, World!
 request finish!!
 0x7ffeefbfe2f8 logMsg
 -[WeakStrongClass dealloc]

结论

  • SimulationRequest单例对象只通过block持有了obj1obj1并没有持有SimulationRequest的单例对象,没有形成循环引用,所以obj1能够执行- logMsg方法并在block执行完成之后销毁

测试二 局部变量Request

WeakStrongClass的对象使用临时创建的SimulationRequest对象进行请求

  • WeakStrongClass.m
- (void)request2{
    [[SimulationRequest request] simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!!");
        [self logMsg];
    }];
}
  • test
void weakStrongTest2(void) {
    WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
    [obj1 request2];
}
  • 日志输出
 Hello, World!
 request finish!!
 0x7ffeefbfe2d8 logMsg
 -[WeakStrongClass dealloc]

结论

SimulationRequest局部变量并没有进行销毁,但是WeakStrongClass对象执行- logMsg方法并在block执行完成之后销毁

  • 修改weakStrongTest2添加AutoRelease使SimulationRequest对象能够销毁
void weakStrongTest2(void) {
    @autoreleasepool {
        WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
        [obj1 request2];
    }
}
  • 日志输出
 Hello, World!
 request finish!!
 0x7ffeefbfe2f8 logMsg
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

测试三 持有Request

  • SimulationRequest.h
@interface WeakStrongClass: NSObject
@property (nonatomic, strong) SimulationRequest *simRequest;
@end
  • SimulationRequest.m
- (instancetype)init{
    self = [super init];
    if (self) {
        self.simRequest = [SimulationRequest request];
    }
    return self;
}

- (void)request3{
    [self.simRequest simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!!");
        [self logMsg];
    }];
}
  • test
void weakStrongTest3(void) {
    WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
    [obj1 request3];
}
  • 日志输出
 Hello, World!
 request finish!!
 0x7ffeefbfe2d8 logMsg
 -[WeakStrongClass dealloc]

结论

WeakStrongClass对象进行了正常的销毁。虽然obj1->request->Dictionary->obj1行成了一个闭环,但是[self.requestDic removeObjectForKey:@(_idt)];打破了循环,使得obj1对象进行了释放

  • 增加autoreleasepool
void weakStrongTest3(void) {
    @autoreleasepool {
        WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
        [obj1 request3];
    }
}
  • 日志输出
 Hello, World!
 request finish!!
 0x7ffeefbfe2d8 logMsg
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

测试四 字典不移除元素

假设SimulationRequest对失败的请求进行暂存,后续继续存储。但是WeakStrongClass已经不在关注请求情况

  • 注释SimulationRequest的移除操作
    dispatch_async(_kqueue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            reqCompletion reqHandler = [self.requestDic objectForKey:@(_idt)];
            reqHandler(@"hello !");
            //[self.requestDic removeObjectForKey:@(_idt)];
        });
    });
  • 使用weakSelf
- (void)request4{
    __weak typeof(self) weakSelf = self;
    [self.simRequest simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!! *** %@",msg);
        [weakSelf logMsg];
    }];
}
  • test
static WeakStrongClass *_kObj;
void weakStrongTest4(void) {
    @autoreleasepool {
        WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
        [obj1 request4];
        _kObj = obj1;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC), dispatch_get_global_queue(0, 0), ^{
            _kObj = nil;
        });
    }
}

使用WeakStrongClass *_kObj来模拟viewController被展示,同时模拟2秒后退出当前页面

  • 日志
 Hello, World!
 request finish!! *** hello !
 0x7ffeefbfe2e8 logMsg
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

结论

WeakStrongClass现在可以正常释放,不受SimulationRequest的影响

问题,何时使用strongSelf?

假设在block执行过程中,obj1对象被销毁怎样?这是就需要使用strongSelf了

  • 模拟场景
- (void)request5{
   __weak typeof(self) weakSelf = self;
   [self.simRequest simulationRequestCompletation:^(NSString * _Nonnull msg) {
       NSLog(@"request finish!! *** %@",msg);
       [weakSelf logMsg];
       sleep(3);
       [weakSelf logMsg];
   }];
}
  • test
static WeakStrongClass *_kObj;  // 和weakStrongTest4上的‘_kObj’只能存在一个
void weakStrongTest5(void) {
    @autoreleasepool {
        WeakStrongClass *obj1 = [[WeakStrongClass alloc]init];
        [obj1 request5];
        _kObj = obj1;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC), dispatch_get_global_queue(0, 0), ^{
            _kObj = nil;
        });
    }
}

模拟viewController被展示,同时模拟2秒后退出当前页面,但是request5中的回调有耗时操作

  • 日志输出
 Hello, World!
 request finish!! *** hello !
 0x7ffeefbfe2d8 logMsg
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

结论

logMsg只执行了一次,第二次执行时,WeakStrongClass被global线程释放导致weakSelf = nil,第二次logMsg没有执行

  • 增加StrongSelf
- (void)request5{
    __weak typeof(self) weakSelf = self;
    [self.simRequest simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!! *** %@",msg);
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf logMsg];
        sleep(3);
        [strongSelf logMsg];
    }];
}
  • 日志输出
 Hello, World!
 request finish!! *** hello !
 0x7ffeefbfe2d8 logMsg
 0x7ffeefbfe2d8 logMsg
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

结论

logMsg执行了两次,符合预期效果

注意

如果 __strong typeof(weakSelf) strongSelf = weakSelf;执行之前,weakSelf已经是nil,logMsg不执行

  • 修改代码顺序
- (void)request5{
    __weak typeof(self) weakSelf = self;
    [self.simRequest simulationRequestCompletation:^(NSString * _Nonnull msg) {
        NSLog(@"request finish!! *** %@",msg);
        [weakSelf logMsg];
        NSLog(@"will strongSelf");
        sleep(3);
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf logMsg];
    }];
}
  • 日志输出
 Hello, World!
 request finish!! *** hello !
 0x7ffeefbfe2d8 logMsg
 will strongSelf
 -[WeakStrongClass dealloc]
 -[SimulationRequest dealloc]

你可能感兴趣的:(Weak & Strong)