What are the retain count of NSStrings allocations mentioned below - ios

Here I allocated NSString variables ten different ways, and I want to know the retain count for all of them.
#interface SomeClass : NSObject
{
NSString *str1;
NSString *str2;
}
#property (nonatomic, retain) NSString* str1;
#property (nonatomic, copy) NSString * str2;
- str1 =#"hello";
- self.str1 = #"hello";
- str1 = [[NSString alloc]init];
- self.str4 = [[NSString alloc]init];
- str1 = [[[NSString alloc]init]autorelease];
- self.str1 = [[[NSString alloc]init]autorelease];
- str1 = [[NSString alloc]initWithString:#"hello"];
- self.str1 = [[NSString alloc]initWithString:#"hello"];
- str1 = [[[NSString alloc]initWithString:#"hello"]autorelease];
- self.str1 = [[[NSString alloc]initWithString:#"hello"]autorelease];
What are the retain count of NSString allocations mentioned above? How can I know the retain count of them are retain count different for all of them?

While this seems like a homework assignment, you can call retainCount on each string to get an approximation of the real value. You should absolutely not use this method for any logic in a production app (see http://whentouseretaincount.com)! The documentation states:
Special Considerations
This method is of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.

I assume they are accessed in some SomeClass method. Variants:
// replace str1 with str2(copy), retain count will remain the same
str1 = #"hello";
self.str1 = #"hello"
str1 = [[NSString alloc]initWithString:#"hello"];
self.str1 = [[NSString alloc]initWithString:#"hello"];
str1 = [[[NSString alloc]initWithString:#"hello"]autorelease];
self.str1 = [[[NSString alloc]initWithString:#"hello"]autorelease];
Here you'll end up with a huge value, like UINT_MAX, compiler will optimize your code (you pass literal value, NSString is immutable) and those objects will be unreleasable.
self.str1 = [[NSString alloc] initWithFormat:#"a string %d", 5]; // with autorelease or not - the same
Here you'll end up with a release count = 2, you alloc string +1, you assign a retain property +1 = 2.
self.str2 = [[NSString alloc] initWithFormat:#"a string %d", 5]; // with autorelease or not - the same
Here you'll end up with a release count = 1, you alloc string +1, you assign a copy proprty, thus create a copy of created string = 1.
In all other situations you'll end up with release count = 1, autorelease does not add to retain count, it just decrements it by 1 when the pool drains.
Just remember:
Do not rely on retainCount,
When you create object via alloc, new, copy, mutable copy - it's your responsibility to release it. If you create object with like [NSString string] it will be autoreleased.
retain property retains object, copy property copies object, properties are usually used via dot notation (self.property etc.) (there's also set%Property% and %property% methods synthesized, so self.property = ... is (usually) the same as [self setProperty:...])
It's time to move to ARC. So if you can you should.

Related

A developer when going through a code base encounters two different syntaxes for creating a NSString with the given integer. (implemented in MRC)

1. NSString *str1 = [NSString stringWithInt: 10];
2. NSString *str2 = [[NSString alloc] initWithInt: 10];
What is the difference between these methods?
The history goes to times when automatic reference counting doesn't existed.
Then Apple have created notation, that methods with prefixes init, copy, new returns owned pointer, that mean that you don't need to retain it, other methods should return autoreleased pointers. For example
NSString *a;
NSString *b;
#autoreleasepool {
a = [[NSString alloc] initWithFormat:#"%d", 1];
b = [NSString stringWithFormat:#"%d", 2];
NSLog(#"String a in autorelease pool is %#", a); //output: String a in autoreleasepool is 1
NSLog(#"String b in autorelease pool is %#", b); //output: String b in autoreleasepool is 2
}
NSLog(#"String a out of autorelease pool is %#", a); //output: String a out of autorelease pool is 1
NSLog(#"String b in autorelease pool is %#", b); //crash: referencing invalid object, because b was autoreleased but variable `b` still pointing at released object
For proper working outside autoreleasepool variable b should be retained:
NSString *b;
#autoreleasepool {
b = [[NSString stringWithFormat:#"%d", 2] retain];
NSLog(#"String b in autorelease pool is %#", b); //output: String b in autoreleasepool is 2
}
NSLog(#"String b out of autorelease pool is %#", b); //output: String b out of autorelease pool is 1
But if you use retain properties, you will face opposite situation: memory leaks.
Proper code will be
#property (retain) NSString *a;
#property (retain) NSString *b;
#autoreleaspool {
self.a = [[[NSString alloc] initWithFormat:#"%d", 1] autorelease];
self.b = [NSString stringWithFormat:#"%d", 2];
}
So exact implementation of stringWithFormat: is doing alloc+init+autorelease
Of course now when we have ARC we don't need think about proper object retaining and releasing.
In ARC first code snipped will work fine without crashes, second code snippet will work fine without memory-leaks.
So now it's just for programmer sense which one he prefer most. It's like in swift: you can write: SomeClass(...) or SomeClass.init(...)
The first is a class factory method. See http://www.apeth.com/iOSBook/ch04.html#_class_methods_2
The second is a genuine initializer.
The difference between them was much more obvious back in the day of manual memory management. Now that ARC exists, they are indistinguishable — which is why Swift eliminates the former.

Are all objects in the iOS automatically added to the auto release pool?

Are all objects in the iOS automatically added to the autorelease pool?When ARC? If no, which one will be added & which one not?
eg:
{
NSString *str = [[NSString alloc] init];
NSString *str2 = [NSString string];
}
+ (NSString *)string {
return [[NSString alloc] init];
}
str2 will be added to autorelease pool because it creates by a method that name as 'copy/mutableCopy/alloc/new'. So it does not create by self. But I don't know is str will be added or not and why?
ARC makes no guarantees as to what objects are added to the autorelease pool and what objects are not. It is very possible that neither of the objects in your example are ever added to the autorelease pool under ARC.
The answer is NO. In fact, which will be added auto release pool is obj of method "string".
// ARC
{
NSString __strong *str = [[NSString alloc] init]; // STEP A
NSString __strong *str2 = [NSString string]; // STEP B
}// STEP Finish
+ (NSString *)string {
id obj = [[NSString alloc] init];
return obj;
}
Like this may help you understand.In ARC, object has __strong modifier(default).Because a object must has a strong pointer point to it, or it die.
STEP A : str create a NSString object and strong point to itself.
STEP B : str2 not create but strong point to a object which is obj.obj created by NSString in method string, because it needs return, so added to auto release pool. And str2 strong point to obj, so obj can't release by auto release pool, there still a strong pointer point to it.
STEP Finish,str,str2 out of method, no more strong pointer .So they had release.
At STEP B, why will needs auto release pool? Because if don't put obj into auto release pool, it will release by compiler, just like str in the STEP Finish.
All this from the book "Pro multithreading and memory management for iOS and OS X".
Forget my poor English.

Strong and weak event.NSString [duplicate]

I wrote the following sample code to see how ARC works
#property (nonatomic, weak) NSString *myString;
#property (nonatomic, weak) NSObject *myObj;
#end
#implementation ViewController
#synthesize myString = _myString;
#synthesize myObj = _myObj;
- (void) viewDidAppear:(BOOL)animated
{
NSLog(#"Appearing Obj: !%#!",self.myObj);
NSLog(#"Appearing String: !%#!",self.myString);
}
- (void)viewDidLoad
{
self.myObj = [[NSObject alloc] init];
self.myString = [[NSString alloc] init];
NSLog(#"Loading Obj %#",self.myObj);
NSLog(#"Loading String: !%#!",self.myString);
}
However surprisingly I got these results:
2012-06-19 15:08:22.516 TESTER[4041:f803] Loading Obj (null)
2012-06-19 15:08:22.517 TESTER[4041:f803] Loading String: !!
2012-06-19 15:08:22.533 TESTER[4041:f803] Appearing Obj: !(null)!
2012-06-19 15:08:22.535 TESTER[4041:f803] Appearing String: !!
As you can see, Obj got released properly but my string (which is also a weak property) does not print out null...Why not?
NSString uses all sorts of internal trickery to reuse objects and avoid unnecessary allocations and copies. It can do this because NSString instances are immutable. In this case there is probably a shared instance to represent an empty string which is being returned by [[NSString alloc] init], and this shared instance will be retained somewhere else as a singleton.
[[NSString alloc] init] always returns identical value. You can check it by yourself.
NSString *string1 = [[NSString alloc] init];
NSString *string2 = [[NSString alloc] init];
NSString *string3 = [[NSString alloc] init];
NSLog(#"string1 = %p, string2 = %p, string3 = %p", string1, string2, string3)
This code returns three identical addresses. In my case, output was:
string1 = 0x3e8dd74c, string2 = 0x3e8dd74c, string3 = 0x3e8dd74c
That means [[NSString alloc] init] returns Singleton. Singletons usually can't be released.
Making strings with other methods (like initWithFormat:) makes usual 'non-singleton' objects, which usually can be released, with some exceptions.
Further:
Looking source code (Assembler):
-[NSPlaceholderString init]:
00040ea4 f64b009c movw r0, 0xb89c
00040ea8 f2c00016 movt r0, 0x16
00040eac 4478 add r0, pc
00040eae 4770 bx lr
it would be something like this (in objectiveC)
-(id)init
{
return SOME_CONSTANT_VALUE;
}
It might be kCFEmptyString, but I'm not sure.

Why two strings allocated with NSString *str1 = [[NSString alloc]init]; have same address?

NSString *str1 = [[NSString alloc]init];
NSString *str2 = [[NSString alloc]init];
NSLog(#"%p\n%p",str1,str2);
result
str1:0x7fff7b559d00
str2:0x7fff7b559d00
Why str1 and str2 have same memory address?
NSString is immutable, so two empty strings are identical. Therefore, Cocoa can return the same object every time you create it.
The real question, however, how can this be done when alloc returns two different addresses for the two strings?
The answer is that init is allowed to substitute the value of self for anything it wishes, and return a completely different object. For example, NSString's init can be implemented like this:
-(id)init {
static NSString *empty = nil;
if (!empty) {
empty = [[NSString alloc] initWithCharacters:"" length:0];
}
return empty;
}
Note: The real code in Cocoa will almost certainly be different; this is only an illustration to show how the same address could be returned for different allocations.

Why is autorelease object still alive?

I've created autorelease pool. localString has added to this pool. I released the pool. localString and string must be deallocated. But in reality they are still alive. You can see my log:
Why is the string object still alive? I don't know.
and code:
-(NSString*) happyString
{
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
return localString;
}
-(IBAction) onButton:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string = [self happyString];
[pool release];
NSLog(#"Why is the string object still alive? %#", string);
}
Strings (NSString instances and statically allocated strings with #"") are immutable in Cocoa, so when you try to create a new NSString from a statically allocated one, the NSString class can make an optimisation: a new NSString instance is not created (the object created when you called -alloc is immediately released), and the reference to your statically allocated string is returned. That is, the line:
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
Is actually equivalent to:
NSString *localString = #"I don't know.";
(If you check the memory addresses of those two objects, you can see that they are the same.)
As this type of string cannot be released, it does not disappear when you expect it to.
If you were to create your string in a way that cannot be optimised, for example:
NSString *localString = [[[NSString alloc] initWithFormat:#"%#", #"I don't know."] autorelease];
Then your code will behave as you expect, and your application will (hopefully) crash at your NSLog line.
If you have tried any classes (any custom classes) other than NSString , then it would not be alive..

Resources