如何在ARC下使用`-retainCount`方法和`-dealloc`选择器强制执行?

时间:2013-10-10 14:08:06

标签: objective-c automatic-ref-counting

ARC 下,编译器将禁止使用-retainCount-retain-dealloc-release和{{1}的任何方法或选择器}}

但有时候我想知道运行时的保留计数,或者使用方法调整来交换NSObject的-autorelease方法来做某事。

是否有可能抑制(或绕过)编译器抱怨几行代码?我不想为整个项目或整个文件修改ARC环境。我认为预处理器可以做到,但是怎么做?


附加

谢谢大家给我讲讲-dealloc的用法。但我想知道是否可以强制调用/使用那些禁用的方法/选择器。

我知道-retainCount是完成这项工作的强大工具。但我仍然对这些问题感到好奇。

为什么我要使用Instruments

使用块时,如果未在外部变量上指定-retainCount标识符,则在将块复制到堆中后,块将自动保留块中的外部对象。因此,您需要使用弱自我来避免保留周期,例如:

__weak

但是,当您仅在复制的块中使用实例变量时,它仍会导致保留周期(YES,尽管您未在块中使用任何关键字__weak typeof(self) weakSelf = self; self.completionBlock = ^{ [weakSelf doSomething]; }; )。

例如,在非ARC

self

在复制的块代码之前/之后不使用// Current self's retain count is 1 NSLog(@"self retainCount: %d", [self retainCount]); // Create a completion block CompletionBlock completionBlock = ^{ // Using instance vaiable in the block will strongly retain the `self` object after copying this block into heap. [_delegate doSomething]; }; // Current self's retain count is still 1 NSLog(@"self retainCount: %d", [self retainCount]); // This will cuase retain cycle after copying the block. self.completionBlock = completionBlock; // Current self's retain count is 2 now. NSLog(@"self retainCount: %d", [self retainCount]); ,我认为不会轻易发现在完成块中使用实例变量导致的保留周期。

为什么我要使用-retainCount

我想知道是否可以使用方法调配来监视在调用-dealloc时通过在Xcode控制台上记录消息来解除分配哪个对象。我想替换-dealloc -dealloc的原始实现。

2 个答案:

答案 0 :(得分:23)

根本没有推荐,我不知道你的意图,但听起来不太安全。

不建议使用retainCount

来自AppleDocs:

  

此方法在调试内存管理问题时没有任何价值。   因为任何数量的框架对象都可能保留了一个对象   为了保持对它的引用,同时自动释放   池可能在一个对象上持有任意数量的延迟版本   你不太可能从这个方法中获得有用的信息

如果有任何疑问,请查看以下链接:

http://whentouseretaincount.com/

无论你想做什么,请不要。

对于将来的参考,我将添加一些linsk来帮助您了解内存在iOS中的工作方式。即使您使用ARC,也必须知道(请记住ARC不是垃圾收集器)

Beginning ARC in iOS 5 Tutorial Part 1

Understand memory management under ARC

Memory Management Tutorial for iOS

Advance Memory Managment

当然,一旦你理解了记忆是如何工作的,那么就该学习如何用乐器来描述它:

Instruments User Guide

答案 1 :(得分:5)

与其他评论者100%同意您不想使用-retainCount这一事实。但是,关于-dealloc

,请回答您的其他问题

你也不想调动-dealloc。如果你认为你想要调整它,你就不明白它是如何工作的。那里有很多优化;你不能只是搞乱它。但是,正如@bbum提示的那样,当对象被释放时,您可以轻松获得通知,这非常有用。

您将关联的对象附加到要观看的内容。当您想要观看的内容消失时,相关对象也会消失,您可以覆盖其dealloc以执行您想要的任何操作。显然你需要小心一点,因为你处于dealloc的中间,但你通常可以做任何你需要的东西。最重要的是,对于许多情况,您可以在此处设置断点或添加日志记录语句,以便查看对象的发布位置。这是一个简单的例子。

使用ARC

const char kWatcherKey;

@interface Watcher : NSObject
@end

#import <objc/runtime.h>

@implementation Watcher

- (void)dealloc {
  NSLog(@"HEY! The thing I was watching is going away!");
}

@end

NSObject *something = [NSObject new];
objc_setAssociatedObject(something, &kWatcherKey, [Watcher new], 
                         OBJC_ASSOCIATION_RETAIN);

没有ARC

const char kWatcherKey;

@interface Watcher : NSObject
- (void)lastRetainDone;
@end

#import <objc/runtime.h>
// turn off ARC!
@implementation Watcher
{
    BOOL noMoreRetainsAllowed;
}

- (void)lastRetainDone {
   noMoreRetainsAllowed = YES;
}

- (id) retain {
     if (noMoreRetainsAllowed) abort();
     return [super retain];
}

- (void)dealloc {
  NSLog(@"HEY! The thing I was watching is going away!");
  [super dealloc];
}

@end

...

NSObject *something = [NSObject new];
Watcher *watcher = [Watcher new];
objc_setAssociatedObject(something, &kWatcherKey, watcher, 
                         OBJC_ASSOCIATION_RETAIN);
[watcher lastRetainDone];
[watcher release];

现在,当something消失时,-[Watcher dealloc]将会启动并为您登录。很容易。完全支持和记录。


编辑:

  

在复制的块代码之前/之后不使用-retainCount,我认为不会轻易发现在完成块中使用实例变量导致的保留周期。

你在这里有点正确,但有两个要吸取的教训,也就是使用retainCount(在这种情况下实际上对你无实际帮助,因为retainCount经常可以你没想到的东西。)

  • 第一课是:不要在ObjC代码中允许任何警告。您描述的情况通常会在最新版本的clang中创建编译器警告。所以在很多情况下很容易发现它。你将它分成多个赋值的方式,编译器可能会错过它,但是那里的教训是改变你的编码风格以帮助编译器帮助你。
  • 第二个教训是:不要直接在init和dealloc之外访问ivars。这是可能导致的许多小惊喜之一。使用访问者。