我们知道在一个类中用@property声明属性,编译器会自动帮我们生成成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表(ivarslist)。所以在分类中用@property声明属性,既无法生成成员变量也无法生成setter/getter。
可以通过runtime动态绑定解决
#import <objc/runtime.h>
static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey"; //定义一个key值
@implementation Programmer (Category)
//运行时实现setter方法
- (void)setNameWithSetterGetter:(NSString *)nameWithSetterGetter {
objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}
//运行时实现getter方法
- (NSString *)nameWithSetterGetter {
return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}
@end
问:为什么给UIView增加分类添加 x,y,width,height等属性时只需要重写set,get方法,不用设置关联属性啊?
UIView(frame)分类不用runtime动态绑定的原因是:我们只需要用到自己定义属性的setter,
getter方法去设置,返回UIView“本身就有的属性”。而正常情况下,自己定义的属性,setter是设置自定义属性的值,getter也是返回自定义属性的值,而此时分类是没有 “_” 开头的自定义属性字段的,必须动态绑定. 及分类中没有带下划线的成员变量,不能给没有的成员变量赋值
__weak与weak基本相同。前者用于修饰变量(variable),后者用于修饰属性(property)。__weak 主要用于防止block中的循环引用。
__block也用于修饰变量。它是引用修饰,所以其修饰的值是动态变化的,即可以被重新赋值的。__block用于修饰某些block内部将要修改的外部变量。
__weak和__block的使用场景几乎与block息息相关。而所谓block,就是Objective-C对于闭包的实现。闭包就是没有名字的函数,或者理解为指向函数的指针。
__weak修饰符:
1.若附有__weak修饰符的变量所引用的对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态。
2.使用附有__weak修饰符的变量,即是使用注册到autoreleasepool中的对象。
分析1:
{id __weak obj1 = obj},假设obj附加__strong修饰符且对象被赋值。
/编译器的模拟代码/
id obj1;
objc_initWeak(&obj1,obj); //初始化
obj_destoryWeak(&obj1);//变量作用域结束时调用以释放变量
首先通过obj_initWeak函数初始化附有__weak修饰符的变量obj1为0,然后会将赋值对象obj作为参数调用objc_storeWeak函数
objc_storeWeak(参数1,参数2)会将第二个参数作为键值,将第一个参数作为value,注册到weak表中,但是如果第二个参数为0,则是将注册到weak表中的value值删除
obj1=0;
objc_storeWeak(&obj1,obj);
此处是将赋值对象obj的地址作为键值key,将第一个参数的附有__weak修饰符的变量obj1的地址注册到weak表中。
作用域结束时释放变量,先调用obj_destoryWeak(&obj1),然后obj_destoryWeak函数将0作为参数调用objc_storeWeak
objc_storeWeak(&obj1,0);这样会吧变量的地址从weak表中删除
weak表与引用计数表相同,作为散列表被实现。如果使用weak表,将废弃对象的地址(此处是obj的地址)作为键值进行检索,就能高速的获取对应的附有__weak修饰符的变量地址(即obj1的地址)。另外,由于一个对象可以同时赋值给多个附有__weak修饰符的变量中,所以对于一个键值,可以注册多个变量的地址。
释放对象时,对象将通过objc_release函数释放。
(1)objc_release
(2)因为引用计数为0,所以执行dealloc
(3)_object_rootDealloc
(4)object_dispose
(5)objc_destructInstance
(6)objc_clear_deallocating
对象被废弃时最后调用的objc_clear_deallocating函数的动作如下:
a>从weak表中获取废弃对象地址为key的记录
b>将包含在记录中的所有附有__weak修饰符的地址(obj1的地址)赋值为nil
c>从weak表中删除该记录
d>从引用技术表中删除废弃对象(obj)地址为key的记录
从而达到附有__weak修饰符的变量所引用的对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态。另外可以看到,如果大量使用附有__weak修饰符的变量,则会消耗相应的CPU资源,良策是只在需要避免循环引用时使用附有__weak修饰符。
分析2:
为什么在访问附有__weak修饰符的变量时必须访问注册到autoreleasepool的对象呢?
因为__weak修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象有可能被废弃。如果把要访问的对象注册到autoreleasepool中,那么在@autoreleasepool块结束前都能确保该对象的存在。因此,在使用附有__weak修饰符的变量时就必须要使用注册到autoreleasepool中的对象
网友评论