学习了部分runtime的知识后,准备动手做个有意思的东西来见证自己最近学习的成果。
就写一个debug环境下对象的监控的demo吧。
在OC中,所有对象均是继承来自NSObject,所以
实现步骤:
1.我们要利用Category创建一个NSObject的分类,就叫Debug.h吧,加入两个接口用来供外界启动检测。
2.延迟判断该对象是否正常销毁,需要创建一个服务类,为了避免服务类自身的循环引用,需要创建一个代理类来保存启动的服务对象(是否必要?__weak 代替),在服务类的初始化中初始化代理类,然后启动服务,
3.那怎么判断对象是否正常销毁呢?(使用关联对象将服务类的self绑定到目标对象,目标对象销毁,则self销毁,服务不启动),如果self未销毁,则启动服务,启动时,在代理类中可以使用消息转发机制获取服务类的对象。
代码exp:
// NSObject+Debug.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Debug)
//. 增加两个接口来判断对象是否正常销毁
- (void)judgeDeallocation;
- (void)judgeDeallocationAfterDelay:(NSTimeInterval)delay;
@end
NS_ASSUME_NONNULL_END
// NSObject+Debug.m
#import "NSObject+Debug.h"
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface JudgeDeallocationTimerProxy : NSObject {
__weak id helper;
}
@end
@implementation JudgeDeallocationTimerProxy
- (id)initWithHelper:(id)object {
self = [super init];
if (self) {
helper = object;
}
return self;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
return helper;
}
@end
@interface JudgeDeallocationHelper : NSObject {
NSTimer *timer;
JudgeDeallocationTimerProxy *proxy;
__weak id object;
}
@property (retain, nonatomic) NSTimer *timer;
@property (retain, nonatomic) JudgeDeallocationTimerProxy *proxy;
+ (void)judgeDeallocation:(id)object afterDelay:(NSTimeInterval)delay;
@end
@implementation JudgeDeallocationHelper
@synthesize timer, proxy;
static const char JUDGE_DEALLOCATION_HELPER_KEY = 0;
+ (void)judgeDeallocation:(id)object afterDelay:(NSTimeInterval)delay {
#ifdef DEBUG
[[self alloc] initWithObject:object withDelay:delay];
#endif
}
- (id)initWithObject:(id)anObject withDelay:(NSTimeInterval)delay {
self = [super init];
// __weak __typeof(self)weakSelf = self;
if (self) {
object = anObject;
objc_setAssociatedObject(object, &JUDGE_DEALLOCATION_HELPER_KEY, self, OBJC_ASSOCIATION_RETAIN);
self.proxy = [[JudgeDeallocationTimerProxy alloc] initWithHelper:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:delay
target:self.proxy
selector:@selector(judgeTrigger)
userInfo:nil
repeats:NO];
}
return self;
}
- (void)dealloc {
[self.timer invalidate];
self.timer = nil;
self.proxy = nil;
}
- (void)judgeTrigger {
NSLog(@"%@ dealloc is failed! Please check it!", NSStringFromClass([object class]));
}
@end
@implementation NSObject (Debug)
- (void)judgeDeallocation {
[self judgeDeallocationAfterDelay:0];
}
- (void)judgeDeallocationAfterDelay:(NSTimeInterval)delay {
[JudgeDeallocationHelper judgeDeallocation:self afterDelay:delay];
}
@end
|