2

I came across CFGetRetainCount while seeking for a way to log out how many references I've got on my iOS program at a moment in time.

As far as I could see, it shares the retain count for a given instance, which looks pretty much what I needed.

In fact, while playing with it in a blank Swift Playground, I could see the results change when I point a new reference for the instance I've created.

The odd part is - it is always starting at 2. Even for new instances. Why does it happen? Shouldn't it start at 1?

Here's my implementation:

import CoreFoundation

class John: NSObject {
    deinit {
        print("This john is gone")
    }
}

var lilJohn: John? = John()
var bigJohn: John? = John()

CFGetRetainCount(lilJohn) // prints 2
CFGetRetainCount(bigJohn) // prints 2

// I've thought the "2" was because CFGetRetainCount was strongly capturing the argument when inputed, but...
weak var _lilJohn = lilJohn
weak var _bigJohn = bigJohn

CFGetRetainCount(_lilJohn) // still printing 2
CFGetRetainCount(_bigJohn) // same as above

Disclaimer: I'm aware that CFGetRetainCount should only be used for debugging matters. I'm not using such function in a distributed app. This is not going live at all.

I also know CFGetRetainCount results can't be trusted, as it doesn't share when/where the retain/release are being placed. I've found also the isKnownUniquelyReferenced API, but what I'm really after is a count of references, not a boolean.

Rici
  • 1,014
  • 2
  • 12
  • 21
  • 1
    *“I also know CFGetRetainCount results can't be trusted”* – exactly. For example, passing the object to the CFGetRetainCount function might increase the refcount temporarily. Or the Playground might keep a reference. – Martin R Aug 11 '19 at 18:32
  • @MartinR thank you for your reply, in fact thats the statement I'm looking for. Can you share your sources, please? – Rici Aug 11 '19 at 18:33
  • 2
    https://stackoverflow.com/questions/4636146/when-to-use-retaincount, http://www.friday.com/bbum/2011/12/18/retaincount-is-useless/, http://sdarlington.github.io- – Martin R Aug 11 '19 at 18:34
  • 1
    Or this: https://stackoverflow.com/a/38367647/1187415: *“The way you are logging can affect the results, you might get a temporary ownership when logging, therefore increasing all your printing results by 1.”* – Martin R Aug 11 '19 at 18:36
  • "I'm aware that CFGetRetainCount should only be used for debugging matters." This isn't quite true. It is almost completely useless for debugging as well, as you've discovered here. It's hard to state emphatically enough how little information CFGetRetainCount provides. – Rob Napier Aug 11 '19 at 18:39
  • @MartinR you rock, thank you for the responses. I was presuming the playground was keeping a reference itself, indeed. Unfortunately I couldn't find any official resource asserting that. – Rici Aug 11 '19 at 18:39
  • @RobNapier I do agree we can black-box test it and realize the results aren't as expected, but according to Apple's documentation it still can be used for debugging memory leaks, indeed. Perhaps the way I'm doing it is wrong, using swift automatically managed objects. I might use Core Foundation Types instead? Thanks anyway for your thoughts. – Rici Aug 11 '19 at 18:43
  • 2
    But a more important lesson is that you should avoid Playgrounds for any low-level implementation investigations. Playgrounds plays a lot of tricks on you (mostly to display things in the right-hand gutter) that make understanding the internals much harder. The right tool is almost always a command-line app, particularly when coupled with `swiftc -emit-sil`, which will give you a lot of visibility into what's really happening. – Rob Napier Aug 11 '19 at 18:43
  • If you're interested in CoreFoundation memory management, yes, you could explore that with CFGetRetainCount against CoreFoundation types (i.e. in C). It will *still* mislead you pretty often, but it's a start. For example of why it's confusing, get the retain count of `CFSTR("TEST")`. But once you enter ARC, let alone Swift, things get wildly more tricky, and your better bet is to study the SIL and see what really is retained and released rather than looking at CFGetRetainCount. – Rob Napier Aug 11 '19 at 18:50
  • (Just one more thing, and I really will be done :D I probably sound way too much like "don't go poking there; it's all dragons and you're never going to understand it" here, and that's a really bad tone for me to take. You definitely can understand what's going on, and your question isn't bad. We all have a bit of a knee-jerk reaction to retainCount. But digging into the details of memory management is a good thing, and you should keep going, and CFGetRetainCount isn't random, so there is a *reason* for each return, and it's not wrong to figure it out.) – Rob Napier Aug 11 '19 at 18:55

0 Answers0