NSString length and retainCount. Clarification needed
Based on the following code, please advise
NSString *str= [[NSString alloc] initWithString:@"Hello world"];
NSLog(@"Length: %lu\n", [str length]); // 11
NSLog(@"Retain count is %lu\n", [str retainCount]); //1152921504606846975
[str release];
NSLog(@"%lu\n", [str length]); 开发者_开发百科 // 11
NSLog(@"Retain count is %lu\n", [str retainCount]); //1152921504606846975
Originally I was wondering why the number was so large but then saw a a post explaining it. Let me ask this instead ... Why does this number change greatly whether i use
%d
vs%lu
. Originally, i used%d
, but got a warning saying that "Conversion specified type int but the argument has the type NSUInteger (aka unsigned long). A fix was to change%d
to%lu
"Why doesn't the retain count decrement? Large number still shows up unchanged, after the
str
is sentrelease
Why am i still able to access the
str
, after it was sentrelease
?
This may be a hard answer to accept, but it's what you should do:
- Don't worry about it. (in terms of %d/%lu, those specifiers simply expect different data types, and %d (int) has a much smaller and different range from %lu (unsigned long))
- Don't worry about it.
- Don't do it, and especially don't rely on it.
It may be because you started with a constant string (@"Hello world"
) that the memory isn't being deallocated when you call release, and the retainCount is large. But if you have to care about the retainCount, you're doing it wrong.
You are releasing the string in the right place, and that's what matters — don't ever try to use it later.
ultimately, the behaviour is defined by the implementation of NSString -- just use retain/release properly in every case and you will be safe.
what's likely happening: NSString literals are immortal. you can write while (1) { [@"String" release]; }
and there will be no issue.
the copy ctor you have called is likely returning a pointer to the string literal. in pseudocode:
- (id)initWithString:(NSString *)str
{
self = [super init];
if (self != nil) {
if ([str _isStringLiteral] || [str _isImmutable]) {
[self release];
return [str retain];
}
...
}
in this case, you are returned the pointer to the string literal, when passed through [[NSString alloc] initWithString:stringLiteral]
. since sending release
to the immortal string literal does nothing, you can see why it is still a valid object following what you could presume is a released object.
never rely on such details/optimizations, just use normal lifetimes and ref counting and you'll be fine.
精彩评论