解释 alloc/init 发生两次

发布于 2024-12-11 17:25:53 字数 407 浏览 0 评论 0原文

我知道这个问题可能听起来很愚蠢,但请耐心听我说。我构建了一个应用程序来帮助新开发人员了解 iPhone 上的内存保留(还没有 ARC)。它简单明了,4 个按钮,初始化、访问、保留和释放。非常不言自明。我正在显示我的字符串对象的保留计数,该对象是我们戳和戳的目标。 (请不要讲授 [myVar keepCount] 的使用,我已经知道了)

这个东西永远不会进入实际的应用程序,只是为了好玩而玩弄它,希望能帮助人们了解内存是如何工作的。我的保留和释放都工作得很好。我的问题是,如果我调用 myString = [[NSMutableString alloc] init]; 为什么我的保留计数会回落到 1再次。我可以将保留计数增加到 40,但在调用 alloc/init 后我又回到零。我没有泄漏任何地方,只是好奇如果/当再次调用 alloc/init 时 myString 会发生什么。

I realize this question may sound dumb, but just bear with me. I built an app to help new developers wrap their head around memory retention on the iPhone (no ARC yet). It is plain and simple, 4 buttons, init, access, retain, and release. Pretty self explanatory. I am displaying what the retain count for my string object that is the target of our poking and prodding. (Please no lectures on use of [myVar retainCount], I already know)

This stuff will never make it into actual apps, just toying with it for fun and hopefully help someone learn how memory works. My retain and release all work great. My question is that why does my retain count drop back to 1 if I call myString = [[NSMutableString alloc] init]; again. I can boost my retain count to 40, but after calling alloc/init I go back to zero. I am not leaking anywhere, just curious what happens to myString if/when alloc/init is called on it again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟凡古楼 2024-12-18 17:25:53

我的问题是,如果我调用,为什么我的保留计数会回落到 1
myString = [[NSMutableString alloc] init]; 再次?


因为你没有理解 Objective-C 的一个非常基本的概念; myString 不是 NSMutableString 的实例,而是对实例的引用。如果您这样做:

myString = [[NSMutableString alloc] init];
myString = [[NSMutableString alloc] init];

您现在有两个 NSMutableString 实例,其中一个已泄漏。

如果您:

myString = [[NSMutableString alloc] init];
otherString = myString;

您现在有一个带有两个引用的 NSMutableString 实例。

在所有三个分配中,NSMutableString 实例的保留计数将+1,因此,您必须用单个release 来平衡每个分配,否则就会发生泄漏。

将保留计数视为绝对计数是一条通往疯狂的道路。或者,充其量,绝对保留计数的有用范围非常有限,以至于学习它不适用于现实世界的 iOS 编程。


值得重复的是:

对象的 retainCount 是一件棘手的事情。

如果您要继续沿着这条路走,您应该注意以下细节:

  • retainCount 永远不能返回 0
  • 消息,悬空指针不能保证崩溃,
  • 一旦传递了对象,就无法知道保留计数由于实现细节,通过任何系统 API,
  • 任何系统类的任何子类都可能具有未知的保留计数,因为实现细节
  • 保留计数永远不会反映对象是否自动释放
  • 自动释放实际上是线程特定的,而保留计数是线程全局的
  • 某些类是用单例实现了一些 时间(NSString,NSNumber 的某些值)
  • 实现细节随平台和版本的不同而变化的
  • 尝试调配 retain/release/autorelease 不会工作,因为有些类实际上并不使用这些方法来维护保留计数(实现细节、每个平台/版本的更改等。)

如果您要教授保留/释放,您应该对待保留算作增量并完全关注“如果您增加 RC,就必须减少它”。

My question is that why does my retain count drop back to 1 if I call
myString = [[NSMutableString alloc] init]; again?

Because you are failing to understand a very basic concept of Objective-C; myString is not an instance of an NSMutableString, but a reference to an instance. If you were to:

myString = [[NSMutableString alloc] init];
myString = [[NSMutableString alloc] init];

You now have two instances of NSMutableString, one leaked.

If you:

myString = [[NSMutableString alloc] init];
otherString = myString;

You now have a single instance of NSMutableString with two references.

In all three allocations, the NSMutableString instance will have a +1 retain count and, thus, you must balance each with a single release or you'll leak.

Treating retain counts as an absolute count is a path to madness. Or, at best, the scope of usefulness of the absolute retain count is so limited that learning about it is not applicable to real world iOS programming.


This bears repeating:

The retainCount of an object is tricky business.

If you were to continue down this path, you should be aware of the following details:

  • retainCount can never return 0
  • messaging a dangling pointer is not guaranteed to crash
  • retain count cannot be known once you have passed an object through any system API due to implementation details
  • any subclass of any system class may have an unknown retain count due to implementation details
  • retain count never reflects whether or not an object is autoreleased
  • autoreleases is effectively thread specific while the retain count is thread global
  • some classes are implemented with singletons some of the time (NSString, certain values of NSNumber)
  • the implementation details change from platform to platform and release to release
  • attempting to swizzle retain/release/autorelease won't work as some classes don't actually use those methods to maintain the retain count (implementation detail, changes per platform/release, etc..)

If you are going to teach retain/release, you should be treating the retain count as a delta and focus entirely on "If you increase the RC, you must decrease it".

三生一梦 2024-12-18 17:25:53

当您调用 myString = [[NSMutableString alloc] init]; 时,您并不是“再次调用 alloc/init”。您没有在您拥有的同一实例上调用方法。您正在分配并初始化一个新实例,这是一个与之前的对象完全不同的对象。

如果您使用一个包含您保留的对象的变量来执行此操作,那么是的,您正在泄漏它。

when you call myString = [[NSMutableString alloc] init];, you're not "calling alloc/init on it again". You're not calling a method on the same instance you had. You're allocating and initializing a new instance, a completely different object from the one you had before.

And if you're doing that with a variable that had an object that you retained, then yes, you are leaking it.

划一舟意中人 2024-12-18 17:25:53

试试这个。

NSString *myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
for (int i = 1; i < 40; i++)
    [myString retain];
NSLog(@"%d", [myString retainCount]); // "40"

NSString *backup = myString;
myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
NSLog(@"%d", [backup retainCount]); // "40"

您会看到,您有一个具有新保留计数的不同对象。您的原始对象仍然存在并且仍然具有相同的保留计数。赋值改变了变量引用的对象。变量没有保留计数,而对象有。

myString = someOtherString;
NSLog(@"%d", [myString retainCount]); // who knows?

保留财产:

self.iString = backup;
NSLog(@"%d", [self.iString retainCount]); // "41" - 1 more because property retained
NSString *newString = [[NSMutableString alloc] init];
NSLog(@"%d", [newString retainCount]); // "1"
self.iString = newString;
// 1 for alloc 1 for retain (in real code you should release newString next)
NSLog(@"%d", [self.iString retainCount]); // "2"
NSLog(@"%d", [backup retainCount]); // "40" - self.iString released it

Try this.

NSString *myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
for (int i = 1; i < 40; i++)
    [myString retain];
NSLog(@"%d", [myString retainCount]); // "40"

NSString *backup = myString;
myString = [[NSMutableString alloc] init];
NSLog(@"%d", [myString retainCount]); // "1"
NSLog(@"%d", [backup retainCount]); // "40"

You see, you have a different object with a new retain count. Your original object still exists and still has the same retain count. Assignment changes the object a variable refers to. A variable doesn't have a retain count, an object does.

myString = someOtherString;
NSLog(@"%d", [myString retainCount]); // who knows?

With retained property:

self.iString = backup;
NSLog(@"%d", [self.iString retainCount]); // "41" - 1 more because property retained
NSString *newString = [[NSMutableString alloc] init];
NSLog(@"%d", [newString retainCount]); // "1"
self.iString = newString;
// 1 for alloc 1 for retain (in real code you should release newString next)
NSLog(@"%d", [self.iString retainCount]); // "2"
NSLog(@"%d", [backup retainCount]); // "40" - self.iString released it
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文