0

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

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

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


补充:

谢谢大家给我上一课关于使用-retainCount. 但我想知道是否可以强制调用/使用那些被禁止的方法/选择器。

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

为什么我要使用-retainCount

使用块时,如果不指定__weak外部变量的标识符,块复制到堆后,块会自动保留块中的那些外部对象。所以你需要使用弱自我来避免保留循环,例如:

__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
    [weakSelf doSomething];
};

但是,当您只在复制的块中使用实例变量时,它仍然会导致保留循环(是的,尽管您没有self在块中使用任何关键字)。

例如,在非 ARC下:

// 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

我想知道我是否可以使用方法调配来监视哪个对象将在-dealloc调用时通过在 Xcode 控制台上记录消息来释放。我想替换-dealloc.NSObject

4

2 回答 2

23

根本不建议这样做,我不知道您的意图,但它们听起来不太安全。

retainCount不推荐使用。

来自 AppleDocs:

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

而且,如果有任何疑问,请查看此链接:

http://whentouseretaincount.com/

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

为了以后的参考,我将添加一些 linsk 来帮助您了解内存在 iOS 中是如何工作的过程。即使您使用 ARC,这也是必须知道的(请记住,ARC 不是垃圾收集器)

iOS 5 教程第 1 部分中的 ARC 入门

了解ARC下的内存管理

iOS 内存管理教程

高级内存管理

当然,一旦您了解了记忆的工作原理,就该学习如何使用仪器对其进行分析了:

仪器用户指南

于 2013-10-10T14:09:08.587 回答
5

与其他评论者 100% 同意您不想使用-retainCount. 但是,对于您的另一个问题,关于-dealloc

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

您将关联的对象附加到要观看的事物上。当您想要观看的内容消失时,关联的对象也会消失,您可以覆盖它dealloc以执行您想要的任何操作。显然你需要小心一点,因为你在 a 的中间dealloc,但你通常可以在这里做大部分你需要做的事情。最重要的是,在很多情况下,您可以在此处放置断点或添加日志语句,这样您就可以看到对象被释放的位置。这是一个简单的例子。

带弧

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。这是可能导致的众多小惊喜之一。使用访问器。
于 2013-10-10T19:37:08.350 回答