iOS开发攻城狮的集散地iOS开发

IOS 用Runtime给分类添加属性、方法

2017-05-09  本文已影响1219人  上帝是个女孩丶

分类的作用:可以在不修改原来类的基础上,为一个类扩展方法。该方法可以不写实现。

扩展(extension)是category的一个特例,有时候也被称为匿名分类。他的作用是为一个类添加一些私有的成员变量和方法。多用于.m 

@interface ViewController ()

@end

这就是最简单的扩展,扩展只介绍这么多。

1.分类创建方法:

分类创建完毕。

我这里是创建了两个分类,一个用于测试公有,一个用于测试私有.

说一下为什么创建两个,有时候会根据不同业务去创建不同的分类。或者类过大也会创建多个分类。

接下来说下问题:

1.分类与分类之间的方法和属性不能互相调用,但是都可以调用基类。

2.分类中原则上只能添加私有属性,下面会讲到通过runtime添加公有属性。而且setter和getter方法需要手动实现。

3.分类中方法名字重复的话会优先调用私有的。在本类和分类有相同的方法时,直接覆盖基类方法。

如果有两个分类,他们都实现了相同的方法,如何判断谁先执行?分类执行顺序可以通过targets,Build Phases,Complie Source进行调节,注意执行顺序是从上到下的。(只有两个相同方法名的分类)

category 方法可能会覆盖于同一个类class 的其它 category 中的方法。但也可能被覆盖,因为不法预知他们的加载优先顺序,出现这种情况通常会在编译时出错。如果在一个开发的SDK中使用了类别, 就最好保证类别名不同于使用者的类别名,以及类别方法也不同于使用者的类别方法名, 通常通过加前缀来做到。

注意:这里经过测试,分类的调用跟创建(添加进项目)时间有关,跟调用顺序无关。如果多个分类方法名冲突,会调用最后创建的那一个,前面会被覆盖。(更正一下,创建不是指创建时间,而是指加入项目的时间,即便你去年就创建了分类A,现在创建了分类B。然后先加入B,后加入A。调用的方法还是优先调用A)

另外一点,试验证明,你创建了分类,即便头文件不引入,只要方法名相同,还是会调用后来创建的。因为这代表调用了私有方法。

(这个结论是亲自测试的,网上搜半天并没有得到什么有用的答案。还是自己亲自来靠谱)

4.分类的方法优先级高,但是不可以调用super方法。

接下来介绍一下category添加属性。

由于分类set get方法需要手动实现。所以直接实现方法就行。

这里分别是两种不同类型的属性,基本类型和对象类型。均使用runtime

/*

* id object 给哪个对象的属性赋值

const void *key 属性对应的key

id value  设置属性值为value

objc_AssociationPolicy policy  使用的策略,是一个枚举值,和copy,retain,assign是一样的,IOS开发一般都选择NONATOMIC

objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

*/

源对象,关联时的用来标记是哪一个属性的key(因为你可能要添加很多属性),关联的对象和一个关联策略。

用来标记是哪一个属性的key常见有三种写法:

static NSNumber *numKey;

static void *numKey = &numKey;

static char numKey;

更新:

分类的命名要尽量带前缀,方便区分。

runtime  严谨写法:

- (NSString*)YYURLString{

return  objc_getAssociatedObject(self, ((__bridge void*)PageNavigationURLStringKey));

}

- (void)setYYURLString:(NSString*)urlString{

objc_setAssociatedObject(self, ((__bridge void*)PageNavigationURLStringKey),urlString, OBJC_ASSOCIATION_RETAIN);

}

主要在于前面加了个__bridge void *    实现id类型与void*类型的相互转换。方便通用OC和C指针

否则当遇到对象类型的时候会报错,当然了这个值一般是我们自己定义的,均为字符串。具体参考网址:http://blog.csdn.net/sanpintian/article/details/8139878

拓展:这种利用Runtime赋值的方式,可以将某个对象赋值给某个类,相当于页面间传值,很强大。

上一篇下一篇

猜你喜欢

热点阅读