1、增加中间变量
- NSObject+weak2.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class FengFeedBack;
@protocol FengDelegate <NSObject>
-(void)FengFeedBack:(FengFeedBack *)feedBack message:(NSString *)message;
@end
@interface FengFeedBack:NSObject
@property(nonatomic,weak)id<FengDelegate> 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 <objc/runtime.h>
@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 <Foundation/Foundation.h>
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 <objc/runtime.h>
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 <NSObject: 0x600002c78760>
2021-08-27 12:42:24.280687+0800 textFeng[33008:1202675] Feng 2222 (null)
3、 NSProxy方式
我这里想到了NSProxy,他可以转发消息,又不会造成循环引用的问题,常用于NSTimer和CADisplayLink。那我使用NSProxy作为属性,通过消息转发就可以实现属性功能,其不会循环引用的特性也符合weak的定义。见《iOS之NSTimer循环引用的最佳解决方案》