blueGhost
blueGhost

Reputation: 13

Ios memory management comes out so confused: CFGetRetainCount()

In ARC environment, I allocate a dynamic array of which each element is a pointer to NSObject*. Then use CFGetRetainCount to get the retain count of the NSObject. The result comes out as expected. However, when I change the NSObject to NSString, the retain count comes out as a large number, which confused me so much. I have searched google, but can't find any valuable information. So, can anyone explain? Appreciate any help.

first code snippet:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject* __strong *arr = nil;
        arr = (id __strong *)calloc(2, sizeof(id));
        *arr = [[NSObject alloc]init];
        *(arr + 1) = [[NSObject alloc]init];
        NSLog(@"--->retainCount:%lu -->%@", CFGetRetainCount((__bridge CFTypeRef)*arr), *arr);
        //output:--->retainCount:1 --><NSObject: 0x100103a00>
        *arr = nil;
        *(arr + 1) = nil;
        free(arr);
    }
    return 0;
}

second code snippet:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString* __strong *arr = nil;
        arr = (id __strong *)calloc(2, sizeof(id));
        *arr = [[NSString alloc]initWithString:@"str_01"];
        *(arr + 1) = [[NSString alloc]init];
        NSLog(@"--->retainCount:%lu \n-->%@", CFGetRetainCount((__bridge CFTypeRef)*arr), *arr);
        //output:--->retainCount:1152921504606846975 -->str_01
        *arr = nil;
        *(arr + 1) = nil;
        free(arr);
    }
    return 0;
}

the NSLog outputs confuse me: why the retain count is not "1" in the second code snippet? is there any different compared with the first code snippet?

Upvotes: 0

Views: 402

Answers (1)

Andreas Oetjen
Andreas Oetjen

Reputation: 10219

The thing is that several Foundation classes in Objective C - like NSString, NSArray, NSNumber - don't behave like "normal" user classes. For example, NSNumber is typically a so-called tagged pointer - a pointer at a "illegal" address (which is not divisible by 4 or 8) and represents the value and not an address. NSString, NSArray... are implemented as so-called class clusters, which is a mechanism that exchanges the internal implementation inside the initializer (e.g. returns a different object than the one that was allocated by the alloc call). Most often, NSStrings are interned / atomized, which is a way to allow quick comparisons etc. by simple pointer comparision (instead of strncmp-like byte-by-byte comparisons).

To fall a long story short: You should never rely on retain counts, this is just an implementation detail of the reference counting mechanism.

Upvotes: 1

Related Questions