需求: 实现分类中添加弱引用属性
@interface ViewController (WeakDelegate)
@property (nonatomic, weak) id delegate;
@end
众所周知runtime中关联属性的几种类型如下:
/**
* Policies related to associative references.
* These are options to objc_setAssociatedObject()
*/
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
但如果想实现弱引用的关联对象就无法使用上面任意一条枚举。
这里通过使用block打包/解包的方式完成需求。
首先,定义打包和解包函数:
typedef id weakid;
typedef weakid(^WeakReference)(void);
WeakReference packWeakReference(id ref) {
__weak weakid weakRef = ref;
return ^{
return weakRef;
};
}
weakid unpackWeakReference(WeakReference closure) {
return closure ? closure() : nil;
}
然后,在常规的形式下添加打包和解包即可:
@implementation ViewController (WeakDelegate)
- (void)setDelegate:(id)delegate
{
objc_setAssociatedObject(self, @selector(delegate), packWeakReference(delegate), OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (id)delegate
{
return unpackWeakReference(objc_getAssociatedObject(self, @selector(delegate)));
}
@end
以下为测试代码
@interface ViewController ()
@property (nonatomic, strong) id ref;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *test = [NSObject new];
NSLog(@"%p",test);
NSLog(@"1 == %@", [test valueForKey:@"retainCount"]);
_ref = test;
NSLog(@"2 == %@", [test valueForKey:@"retainCount"]);
self.delegate = test;
NSLog(@"3 == %@", [test valueForKey:@"retainCount"]);
NSLog(@"%p",self.delegate);
}
@end
打印结果:
testCategoryWeakDelegate[65095:1585708] 0x600000208690
testCategoryWeakDelegate[65095:1585708] 1 == 1
testCategoryWeakDelegate[65095:1585708] 2 == 2
testCategoryWeakDelegate[65095:1585708] 3 == 2
testCategoryWeakDelegate[65095:1585708] 0x600000208690