问题:
给类添加category方法时,如果方法名与原类中的方法重名是会‘覆盖’原类的方法(不是真正意义上的覆盖,category方法会添加到方法列表前面)。如果我们想在category中放入一些本该放在dealloc方法中执行的代码,直接在分类里实现dealloc方法显然是不行的,这会对原类本就实现过的dealloc方法造成影响,如果不想动原类中的代码,要怎么实现这个需求?
实现思路:
给类关联一个对象,这个对象是我们自己创建的中间对象。当类创建的实例对象释放时,这个关联对象也会释放,此时关联对象就会执行自己的dealloc方法。如果我们把分类中要执行的dealloc代码放到这个关联属性的block中,让这个关联属性在执行dealloc时执行这个block,这样就达到我们想要达到的目的。
上代码
首先是创建中间类:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TmpObject : NSObject
+ (instancetype)objWithDeallocBlock:(void(^)(void))deallocBlock;
@end
NS_ASSUME_NONNULL_END
#import "TmpObject.h"
@interface TmpObject ()
@property (nonatomic, copy ) void(^deallocBlock)(void);
@end
@implementation TmpObject
- (instancetype)initWithDellocBlock:(void(^)(void))dellocBlock
{
self = [super init];
if (self) {
_deallocBlock = dellocBlock;
}
return self;
}
+ (instancetype)objWithDeallocBlock:(void(^)(void))deallocBlock{
return [[self alloc] initWithDellocBlock:deallocBlock];
}
- (void)dealloc{
!self.deallocBlock?:self.deallocBlock();
}
@end
分类中的实现(这里给UIView添加分类,在UIView的分类中实现皮肤主题切换的监听功能,需要在view释放时移除消息监听):
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (LLThemeAdd)
- (void)addThemeDidChangedNotification;
@end
NS_ASSUME_NONNULL_END
#import "UIView+LLThemeAdd.h"
#import "TmpObject.h"
#import <objc/runtime.h>
@implementation UIView (LLThemeAdd)
static const char kThemeTmpObjKey = '\0';
- (void)addThemeDidChangedNotification{
__weak typeof (self)weakSelf = self;
TmpObject *tmpObj = [TmpObject objWithDeallocBlock:^{
[[NSNotificationCenter defaultCenter] removeObserver:weakSelf];
}];
objc_setAssociatedObject(self, &kThemeTmpObjKey, tmpObj, OBJC_ASSOCIATION_RETAIN);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(themeChanged:) name:@"kThemeDidChangedNotification" object:nil];
}
- (void)themeChanged:(NSNotification *)notification{
NSLog(@"++++++ ThemeDidChanged");
}
@end