分类添加weak属性

1、增加中间变量

  • NSObject+weak2.h
#import 

NS_ASSUME_NONNULL_BEGIN

@class FengFeedBack;
@protocol FengDelegate 

-(void)FengFeedBack:(FengFeedBack *)feedBack message:(NSString *)message;

@end

@interface FengFeedBack:NSObject

@property(nonatomic,weak)id delegate;

-(void)test;

@end


@interface NSObject (weak2)

@property(nonatomic,strong) FengFeedBack *feed;

@end

NS_ASSUME_NONNULL_END
  • NSObject+weak2.m

#import "NSObject+weak2.h"
#import 

@implementation FengFeedBack

-(void)test {
    if (_delegate && [_delegate respondsToSelector:@selector(FengFeedBack:message:)]) {
        [_delegate FengFeedBack:self message:@"test"];
    }
}

-(void)dealloc {
    NSLog(@"FengFeedBack dealloc");
}
@end

@implementation NSObject (weak2)

- (void)setFeed:(FengFeedBack *)feed {
    objc_setAssociatedObject(self, @selector(feed), feed, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (FengFeedBack *)feed {
    return objc_getAssociatedObject(self, @selector(feed));
}

@end
  • 测试使用
@property(nonatomic,strong)NSObject *objec2;

@property(nonatomic,strong)FengFeedBack *feedBack;

-(void)testCatoryWeak { 
    [self.feedBack test];
}

- (NSObject *)objec2 {
    if (!_objec2) {
        _objec2 = [[NSObject alloc] init];
        _objec2.feed = self.feedBack;
    }
    return _objec2;
}

- (FengFeedBack *)feedBack {
    if (!_feedBack) {
        _feedBack = [[FengFeedBack alloc] init];
        _feedBack.delegate = self;
    }
    return _feedBack;
}

- (void)FengFeedBack:(id)feedBack message:(NSString *)message {
    NSLog(@"Feng FengFeedBack 代理回调用 message:%@",message);
}

2、关联策略使用ASSIGN,然后模拟weak的实现,自动置空

这种方式不用增加类的实现方式。 最佳推荐方案

  • NSObject+weak.h
#import 

NS_ASSUME_NONNULL_BEGIN

@interface NSObject (weak)

@property(nonatomic,weak)id weakObjc;

@end

NS_ASSUME_NONNULL_END
  • NSObject+weak.m
#import "NSObject+weak.h"
#import 

typedef void (^DeallocBlock)(void);

@interface NSObject (weak)

@property(nonatomic,copy)DeallocBlock block;

@end

@implementation NSObject (weak)

- (id)weakObjc {
    return objc_getAssociatedObject(self, @selector(weakObjc));
}

- (void)setWeakObjc:(id)weakObjc {
    //⚠️注意 此处是 把block赋值给了weakObjc 把block当中间变量。
    [weakObjc setBlock:^{ //B关联了A中的weakObjc。当B对象释放的时候就会通过A去找weakObjc。所以会触发A的dealloc
        objc_setAssociatedObject(self, @selector(weakObjc), nil, OBJC_ASSOCIATION_ASSIGN);
    }];
    objc_setAssociatedObject(self,  @selector(weakObjc), weakObjc, OBJC_ASSOCIATION_ASSIGN);
}

- (DeallocBlock)block {
    return objc_getAssociatedObject(self, @selector(block));
}

- (void)setBlock:(DeallocBlock)block {
    objc_setAssociatedObject(self, @selector(block), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" //未使用default
- (void)dealloc {
    self.block?self.block():nil;  //weakObjc置空
    objc_setAssociatedObject(self, @selector(block), nil,OBJC_ASSOCIATION_COPY_NONATOMIC);//block置空
}
#pragma clang diagnostic pop

@end
  • 测试使用
    NSObject *obj1 = [NSObject new];
    NSObject *obj2 = [NSObject new];
    obj1.weakObjc = obj2;
    NSLog(@"Feng %@",obj1.weakObjc);
    obj2 = nil; //obj2持有obj1中的weakObjc。obj2为nil为调用obj2的dealloc,会通过obj1去找weakObjc,触发obj1的dealloc
    NSLog(@"Feng %@",obj1.weakObjc);
  • 输出结果
2021-08-27 12:42:24.280552+0800 textFeng[33008:1202675] Feng 1111 
2021-08-27 12:42:24.280687+0800 textFeng[33008:1202675] Feng 2222 (null)

3、 NSProxy方式

我这里想到了NSProxy,他可以转发消息,又不会造成循环引用的问题,常用于NSTimer和CADisplayLink。那我使用NSProxy作为属性,通过消息转发就可以实现属性功能,其不会循环引用的特性也符合weak的定义。见《iOS之NSTimer循环引用的最佳解决方案》

你可能感兴趣的:(分类添加weak属性)