开发过程中发现,一个控制器pop后不会走dealloc
方法,除了一些常见的原因,还有个不容易被发现的问题 —— 该控制器中使用到某个类的Catagory
,而又为Catagory添加了一个属性强引用当前控制器。
但我们都知道在使用runtime关联对象时,只有一下几个属性:
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. */
};
如果我们使用OBJC_ASSOCIATION_RETAIN_NONATOMIC
来修饰这个属性,相当于strong
,就会造成循环引用导致当前视图无法被释放。
- 错误代码:
objc_setAssociatedObject(self, &showInVC, [self getCurrentVC], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
UIViewController *currentVC = objc_getAssociatedObject(self, &showInVC);
因此需要给类别Catagory添加weak属性解决这个问题!
Catagory添加Weak属性
- 新建一个类,用于包裹weak对象
由于 objc_AssociationPolicy
没有weak属性,所有使用object包裹一层
@interface GLCatagoryWeakWrapper : NSObject
@property (nonatomic, weak) id weakObj;
@end
@implementation GLCatagoryWeakWrapper
@end
- 在Catagory中使用
- (void)setWeakCurrentVC {
GLCatagoryWeakWrapper *wrapper = [[GLCatagoryWeakWrapper alloc] init];
wrapper.weakObj = [self getCurrentVC];
objc_setAssociatedObject(self, @selector(getWeakCurrentVC), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)getWeakCurrentVC {
GLCatagoryWeakWrapper *wrapper = objc_getAssociatedObject(self, @selector(getWeakCurrentVC));
return wrapper.weakObj;
}
tips: 因为ObjC的selector的地址是固定的,所以可以用来作为associatedObject的key.