iOS - 自定义引用计数(MRC)
自定义引用计数(Custom Reference Counting)是指类可以通过重写 retain/release 等方法来实现自己的引用计数管理机制。这通常用于特殊场景下的内存管理优化。
1. 判断是否使用自定义引用计数
inline bool
objc_object::hasCustomRR() {
// 检查类是否实现了自定义的引用计数方法
return ISA()->hasCustomRR();
}
// 调用路径
id objc_object::retain() {
if (fastpath(!ISA()->hasCustomRR())) {
// 使用系统默认的引用计数机制
return sidetable_retain();
} else {
// 使用类自定义的引用计数机制
return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
}
}
2. 自定义引用计数的实现示例
@interface CustomObject : NSObject
@property (nonatomic, assign) NSUInteger customRefCount;
@end
@implementation CustomObject
- (id)retain {
@synchronized(self) {
self.customRefCount++;
}
return self;
}
- (void)release {
BOOL shouldDealloc = NO;
@synchronized(self) {
self.customRefCount--;
if (self.customRefCount == 0) {
shouldDealloc = YES;
}
}
if (shouldDealloc) {
[self dealloc];
}
}
- (NSUInteger)retainCount {
@synchronized(self) {
return self.customRefCount;
}
}
3. 使用场景
3.1 单例对象
@implementation MySingleton
+ (instancetype)sharedInstance {
static MySingleton *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[super allocWithZone:NULL] init];
});
return instance;
}
// 防止释放
- (id)retain {
return self;
}
- (oneway void)release {
// 不执行任何操作
}
- (id)autorelease {
return self;
}
3.2 特殊内存管理
@implementation PooledObject
// 对象池中的对象
- (id)retain {
// 不增加引用计数,而是返回到对象池
[[ObjectPool sharedPool] markAsInUse:self];
return self;
}
- (void)release {
// 不真正释放,而是返回到对象池
[[ObjectPool sharedPool] returnToPool:self];
}
4. 注意事项
4.1 线程安全
- (id)retain {
@synchronized(self) {
// 确保线程安全的引用计数操作
_customRefCount++;
}
return self;
}
4.2 内存泄漏防护
- (void)release {
BOOL shouldDealloc = NO;
{
@synchronized(self) {
_customRefCount--;
if (_customRefCount == 0) {
shouldDealloc = YES;
}
}
}
// 在同步块外执行 dealloc
if (shouldDealloc) {
[self dealloc];
}
}
5. 优缺点
优点:
- 可以实现特殊的内存管理策略
- 适合特定场景的优化
- 可以实现对象池等高级功能
缺点:
- 增加代码复杂度
- 可能引入bug
- 需要格外注意线程安全
- 可能影响系统的内存管理优化
6. 最佳实践
@implementation CustomRefCountObject
// 1. 清晰的文档
/**
* 这个类使用自定义引用计数来实现对象池
* 注意:不要直接创建实例,请使用 getFromPool 方法
*/
// 2. 完整的方法实现
- (id)retain {
if (_customManaged) {
return [self customRetain];
}
return [super retain];
}
// 3. 防御性编程
- (void)release {
if (_customManaged) {
[self customRelease];
return;
}
[super release];
}
// 4. 调试支持
- (NSUInteger)retainCount {
if (_customManaged) {
return [self customRetainCount];
}
return [super retainCount];
}
自定义引用计数应该谨慎使用,只在确实需要的特殊场景下采用。大多数情况下,系统默认的引用计数机制就足够了。