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

李岡諭*_*李岡諭 0 objective-c automatic-ref-counting

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

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

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


加法:

谢谢你们给我一个关于使用的教​​训-retainCount.但我想知道是否可以强制调用/使用那些禁止的方法/选择器.

我知道这Instruments是完成这项工作的有力工具.但我对这些问题仍然很好奇.

我为什么要使用-retainCount:

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

__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
    [weakSelf doSomething];
};
Run Code Online (Sandbox Code Playgroud)

但是,当您仅在复制的块中使用实例变量时,它仍将导致保留周期(YES,尽管您未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]);
Run Code Online (Sandbox Code Playgroud)

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

我为什么要使用-dealloc:

我想知道是否可以使用方法调配来监视在-dealloc调用Xcode控制台时通过在Xcode控制台上记录消息来释放哪个对象.我想,以取代原来的执行-deallocNSObject.

Ant*_* MG 23

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

使用的retainCount是不推荐.

来自AppleDocs:

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

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

http://whentouseretaincount.com/

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

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

在iOS 5教程第1部分中开始ARC

了解ARC下的内存管理

适用于iOS的内存管理教程

提前记忆管理

当然,一旦你理解了记忆是如何工作的,就是学习如何用仪器来描述它的时候了:

仪器用户指南

  • 你没有,你使用Instruments来查看你的记忆问题.我知道你想做什么,但是这条道路是徒劳的,你将来会在这一点上结束.认真花时间学习仪器及其功能,您将能够通过使用它找到任何内存问题. (9认同)
  • `-retainCount`只是一个坏主意,期间.不要使用`-retainCount`.相反,正如@ColinWheeler建议的那样,使用仪器; 它为refcounted对象提供了出色的调试工具,非常值得学习利用它们. (2认同)

Rob*_*ier 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);
Run Code Online (Sandbox Code Playgroud)

没有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];
Run Code Online (Sandbox Code Playgroud)

现在,当它something消失时,-[Watcher dealloc]会为你开火并登录.很容易.完全支持和记录.


编辑:

如果不在复制的块代码之前/之后使用-retainCount,我不认为在完成块中使用实例变量导致的保留周期将很容易被发现.

你在这里有点正确,但是有两个教训需要学习,也没有使用retainCount(在这种情况下实际上对你没有帮助,因为这retainCount通常是你不期望的事情).

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

  • 当然!修改观察者类以保存对象类及其地址的引用(只是确保你没有强大的引用.好编辑,Rob,对SOWing FTW! (2认同)