如何實現分類中新增弱引用屬性

swcfsfy發表於2018-07-06

需求: 實現分類中新增弱引用屬性

@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
複製程式碼

完。

相關文章