iOS 给类别(Category)添加weak (property)属性,关联(Associated)

原创 2017年01月03日 17:47:17
Category 在平常代码中经常使用,在使用第三方工具时,遇到工具不能直接解决当前问题的情况,我就会使用到Category,通过给特定的类加一个方法来处理这种情况。

本文仅仅介绍给(Category)加 weak 属性。
weak:修饰OBJC对象,不会持有指向修饰对象,同样指向的对象引用计数就不会增加,当指向的对象被释放释放的时候,weak修饰的对象会被置为nil。
因为堆内存是动态的,所以当某个地址的对象被释放的时候,所有指向他的指针都应该被置为空。weak就是为了满足避免循环引用,同时在对象被释放的时候可以被置为空的情况而存在的。
assign是为了修饰栈内存中的数值对象,当使用assign修饰了一个OBJC对象的时候,可能造成野指针。原因在上面刚刚提到。

进入主题:给 Category 添加 weak 属性。
首先,给 Category 属性是需要使用runtime中的关联来实现set 和 get 方法。但runtime只提供如下几种修饰实现,并没有weak。
**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. */
};**
看了别人的思路之后,加以修改。思路是这样的,虽然runtime没有开放weak解决方案,但OBJC对象是可以实现weak的,所以让需要被修饰的对象去持有一个strong的对象,然后当被修饰的对象被释放的时候,持有的对象也会被释放,那么我们就可以捕捉到释放的事件,进而使用OBJC_ASSOCIATION_ASSIGN 来实现弱引用,在释放事件里面再将其释放掉,进而实现weak功能。
// 定义一个对象,使用block来回调析构函数。
typedef void (^DeallocBlock)();
@interface OriginalObject : NSObject
@property (nonatomic, copy) DeallocBlock block;
- (instancetype)initWithBlock:(DeallocBlock)block;
@end

@implementation OriginalObject

- (instancetype)initWithBlock:(DeallocBlock)block
{
    self = [super init];
    if (self) {
        self.block = block;
    }
    return self;
}
- (void)dealloc {
    self.block ? self.block() : nil;
}
@end

Category添加属性

// Category 
// NSObject+property.h
@interface NSObject (property)
@property (nonatomic, weak) id objc_weak_id;
@end

// NSObject+property.m
@implementation NSObject (property)
- (id)objc_weak_id {
    return objc_getAssociatedObject(self, _cmd);
}

- (void)setObjc_weak_id:(id)objc_weak_id {
    OriginalObject *ob = [[OriginalObject alloc] initWithBlock:^{
        objc_setAssociatedObject(self, @selector(objc_weak_id), nil, OBJC_ASSOCIATION_ASSIGN);
    }];
    // 这里关联的key必须唯一,如果使用_cmd,对一个对象多次关联的时候,前面的对象关联会失效。
    objc_setAssociatedObject(objc_weak_id, (__bridge const void *)(ob.block), ob, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(self, @selector(objc_weak_id), objc_weak_id, OBJC_ASSOCIATION_ASSIGN);
}

具体体验weak 和 assgin的区别:

@property (nonatomic,weak) id      weakPoint;
@property (nonatomic,assign) id    assignPoint;
@property (nonatomic,strong) id    strongPoint;

self.strongPoint = [NSDate date];
self.weakPoint = self.strongPoint;
self.assignPoint = self.strongPoint;
self.strongPoint = nil;
NSLog(@"%p", self.weakPoint); // print 0x0 指针置为空。
NSLog(@"%p", self.assignPoint); // crash 因为self.assignPoint指针指向的对象已经被释放。

测试weak是否正确:

self.strongPoint = [NSDate date];
self.objc_weak_id = self.strongPoint;
self.weakPoint = self.strongPoint;
NSLog(@"%p", self.weakPoint); // print 指针。
NSLog(@"%p", self.objc_weak_id); // print 相同的指针。
self.strongPoint = nil;

NSLog(@"%p", self.weakPoint); // print 0x0 指针置为空。
NSLog(@"%p", self.objc_weak_id); // print 0x0 指针置为空。
在Category中添加 property 相对添加方法少一些,而添加weak property是少之又少,但实现 通过这次实践,你可以明白什么是weak,什么是assign,而不是仅仅知道delegate中用weak,NSInteger用assign。
版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS基础:strong属性与weak属性的区别

一、简介 ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain、release、autorelease语句。你不再需要担心内存管理,因为...
  • gongwutianya
  • gongwutianya
  • 2016年04月01日 08:26
  • 2898

@property的属性weak nonatomic strong等介绍(ios)

学习ios也已经快半个月了,也尝试做简单的应用程序,但是遇到很多问题,总结下来就是:急于求成,总想着做一个东西出来,里面的东西也不懂,只知道把这个复制到代码中就OK了,现在发现基础很重要,所以在此总结...
  • dyllove98
  • dyllove98
  • 2014年12月02日 18:06
  • 8361

iOS - 分类添加属性之关联引用

分类是不能合成属性的,因为合成属性会生成对应的实例变量,而分类是不允许添加实例变量的(实例变量所在内存区域已初始化为不可更改,无法在动态运行时修改之)。 虽然不能增加实例变量,但是添加属性还是可以的...
  • lincsdnnet
  • lincsdnnet
  • 2016年09月04日 22:52
  • 771

iOS中OC给Category添加属性

利用Runtime的关联对象技术给Categroy添加属性
  • Cloudox_
  • Cloudox_
  • 2017年03月19日 16:41
  • 3986

iOS为类别添加属性的方法(RunTime)

一般认为Category不能添加变量,其实系统已经告诉我们是可以的. 这家伙已经给UIViewController添加了图中的几个属性,那么如何实现? 其实是使用@dynamic 来动态添加的。 ...
  • petyou123
  • petyou123
  • 2016年04月15日 14:35
  • 3216

iOS Runtime应用实例(一)类别添加属性

原创Blog,转载请注明出处 http://blog.csdn.net/hello_hwc?viewmode=list 我的stackoverflow 前言:类别添加属性是Runtime最...
  • Hello_Hwc
  • Hello_Hwc
  • 2015年11月10日 10:45
  • 2889

iOS 用类别给类加属性以及原理

oc在类别里给类加属性以及原理如何在类别里给类加属性呢,有鸭子模样的我们就认为他是鸭子了.@interface NSObject (XY) @property (nonatomic, strong) ...
  • uxyheaven
  • uxyheaven
  • 2015年02月05日 18:50
  • 10009

__weak如何实现对象值自动设置为nil的

__weak 修饰符 就像我们知道的那样__weak修饰符提供了如同魔法般的功能。 ● 若使用__weak修饰符的变量引用对象被废弃时,则将nil赋值给该变量 ● 使用附有__weak修饰符的变量,...
  • hherima
  • hherima
  • 2014年08月18日 16:56
  • 3958

iOS开发-------自定义回调

以前一直用系统写的类,比如UIButton,用到的时候我们只需要知道用addTarget方法来回调,产生动作,但是却不知道回调是如何产生的,通过学习,自己写了一个KeyBoard的类,大体运行结果就是...
  • RunIntoLove
  • RunIntoLove
  • 2015年09月22日 16:06
  • 578

iOS非常重要的 block回调

刚刚进入ios开发行业,发现开发中要用到大量的block回调,由此可见它的重要性。学习它之前我也是网上找的资料,推荐这篇文章http://blog.csdn.net/mobanchengshuang/...
  • itpeng523
  • itpeng523
  • 2014年04月22日 19:51
  • 71242
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:iOS 给类别(Category)添加weak (property)属性,关联(Associated)
举报原因:
原因补充:

(最多只允许输入30个字)