Strong and weak event.NSString [duplicate] - ios

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.

Related

NSString : leak when assigning value to a property

Assuming we don't use ARC.
Suppose we have a very simple class in which we declare 2 NSString properties, like this :
#interface Foo : UIView {}
-(id)initWithArguments:(NSString*)mess title:(NSString*)tit;
#property(nonatomic, retain) NSString *message;
#property(nonatomic, retain) NSString *title;
#end
and in implementation :
#implementation Foo
#synthesize message, title;
-(id)initWithArguments:(NSString*)mess title:(NSString*)tit{
if((self = [super init])){
message = mess; // (1)
self.title = tit; // (2)
(...)
}
return self;
}
-(void)dealloc{
message = nil;
title = nil;
[super dealloc];
}
#end
Now if I call a method from another class, in which I create 2 NSString and an instance of Foo , like this :
-(void)someMethod{
NSString *string1 = [NSString stringWithFormat:#"some text with %d things", 5];
NSString *string2 = [NSString stringWithFormat:#"other text with %d things", 5];
Foo *foo = [[Foo alloc] initWithArguments:string1 title:string2];
}
The whole code works fine and doesn't crash, but, if I profile it with instruments,
it doesn't cause a leak when calling (1)("message = mess;")
it cause a leak when calling (2)("self.title = tit;")
It's very confusing, because stringWithFormat is an autoreleased object, isn't it ?
So, how an autoreleased object can cause a leak when assigning to a property ???
I read somewhere that it's almost always better to use the "self.text = value;" form instead of the "text = value;" form, because the second one may cause a leak.
Actually, in this code it's the contrary.
And... If I use a constant NSString like #"some text", instead of the values returned by [NSString stringWithFormat], there is no leak, of course.
Any idea ?
You have forgotten to invoke the (compiler-generated) setter methods in a few cases:
self.message = mess; // in init method
self.message = nil; // in dealloc method
self.title = nil; // ditto
It's crucial that you use the setter/getter methods in non-ARC code.

call to setter gives unrecognized selector error

I'm trying to subclass NSString to give it a property that is another NSString. No matter what I try with #synthesize or #dynamic or manually coding my setters and getters, I keep getting this "unrecognized selector sent to instance" error when I compile.
I know this has probably already been answered but after looking through about 15 other "unrecognized selector" questions on this site I am still at a loss. Sorry, I started coding VERY recently so I'm probably just missing something exceedingly simple.
Furigana.h
#interface Furigana : NSString
#property (strong, nonatomic) NSString *forKanji;
-(void)setForKanji:(NSString *)forKanji; //fails the same with or without this line
#end
Furigana.m
#import "Furigana.h"
#implementation Furigana
#synthesize forKanji = _forKanji;
//#dynamic forKanji; tried this
-(NSString *)forKanji { //also fails when custom setter/getters are left out
if(!_forKanji) _forKanji = [[NSString alloc] init];
return _forKanji;
}
-(void)setForKanji:(NSString *)forKanji {
if(!_forKanji) _forKanji = [[NSString alloc] init];
_forKanji = forKanji;
}
#end
Reibun.m
#import "Furigana.h"
-(NSArray *)parseFurigana:(NSArray *)unparsedData {
NSMutableArray *furigana = [[NSMutableArray alloc] init]; //of Furigana
for(unsigned int x = 0; x < [unparsedData count]; x++){
NSArray *components = [[NSArray alloc] init];
components = [[unparsedData objectAtIndex:x] componentsSeparatedByString:#":"];
Furigana *newFurigana = [[Furigana alloc] init];
newFurigana = [components objectAtIndex:1];
NSLog(#"stored string: %#",newFurigana); //so far so good
newFurigana.forKanji = [components objectAtIndex:0]; //crash
//[newFurigana setForKanji:[components objectAtIndex:0]]; //this fails too
[furigana addObject:newFurigana];
}
return furigana;
}
Here is the line that breaks your code:
newFurigana = [components objectAtIndex:1];
It replaces the object that you have allocated using [[Furigana alloc] init] with an NSString object, which does not respond to setForKanji: selector.
The assignment replaces newFurigana object, not the content of it. The content cannot be changed, because you derive from NSString, which is immutable.
Replace the init with initWithString, call [super initWithString:] from it, and make the initialization inside your loop look like this:
Furigana *newFurigana = [[Furigana alloc] initWithString:[components objectAtIndex:1]];

Objective C, what [NSString initWithFormat] exactly does?

I just would like to know the difference between the line 1 and 2 bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If I asked that question, it is because I got a problem by using MKAnnotation. In the method bellow, I try to update the subtitle delegate property of MKAnnotation (which is nonatomic, copy and readonly). But it's look like that I got a zombie when using the line 2 and nothing when using the line 1. So my question is why?
- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
CLPlacemark *place = [placemarks objectAtIndex:0];
_coordinate = place.location.coordinate;
_title = self.address;
_subtitle = #"Test"; //Line 1: don't crash
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2: crash
//_subtitle = [[NSString stringWithFormat: #"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
_isInit = YES;
[self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];
}
I actually already fixed my problem by using the method copy, but I still not understand what is the difference between the line 1 and 2, if anyone can help me to understand what the difference is, I will appreciate.
Edit:
1- I am not using ARC
2- _subtitle comes form #synthesize subtitle = _subtitle; And subtitle is a part of the MKAnnotation protocol, with the property nonatomic, readonly and copy
Regards,
Cyril
If you are not using ARC, the answer is straightforward and is what Anoop Vaida wrote. However, I think some further explanation is needed.
This line
_subtitle = #"Test";
Creates a reference to a string literal. If you take a peak at its retain count in the current implementation of foundation, you'll find it is a very large number (NSIntegerMax I think). If the code for -release and -retain comes across this value for the retain count, they do not decrement or increment it. Thus string literals have infinite life times.
This line:
_subtitle = [NSString stringWithFormat: #"Test"];
creates a string you do not own. Unless you take steps to claim ownership, it could disappear at any time, most likely when the autorelease pool is drained. Your options are create a string you do own
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
or to retain it.
_subtitle = [NSString stringWithFormat: #"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.
or to copy it
_subtitle = [[NSString stringWithFormat: #"Test"] copy];
Note that, in all cases, you need to release the previous value of _subtitle before you overwrite it, or you will get a leak e.g.
[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
This is why it is better to have a property. Just because the MKAnnotation subtitle property is read only, does not mean you can't override it with your own read/write property. e.g.
#interface MyAnnotation : NSObject <MKAnnotation>
// other stuff
#property (readwrite, copy, nonatomic) NSString* subtitle;
#end
If you then synthesize it, you'll get all the correct memory management code and you can just do
[self setSubtitle: [NSString stringWithFormat: #"test"]];
or, if you must use dot notation
self.subtitle = [NSString stringWithFormat: #"test"];
I just would like to know the difference between the line 1 and 2
bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If you ask just the above these both are same.
While checking your code, the difference is quite visible.
You are creating a new autoreleased subtitle which is getting released once the block is over.
I don't think your solution is to understand how the string initializes work, but more on how blocks deal with variables.
When I think about it I think you may want to try an access _subtitle by it's property and not it's ivar.
self.subtitle
This should increment the retain count and keep everything functioning fine.
If you look up the documentation for initWithFormat: it links you to Formatting String Objects with many examples.
This basically allows (s)printf-style format strings, like so:
NSString *string1 = [[NSString alloc] initWithFormat:#"A string: %#, a float: %1.2f",
#"string", 31415.9265];
// string1 is "A string: string, a float: 31415.93"
The key is to specify arguments by adding a , after the string argument.
The '[NSString stringWithFormat:]' allows you to add a variable into the string, for example:
int myVar = 3;
NSString *myString = [NSString stringWithFormat:#"This number is %i", myVar];
The resulting string would be (if you were to NSLog it, for example): "This number is 3"
However you cannot do it like this:
NSString *myString = #"This number is %i", myVar;
Which would present you with an error.

What are the retain count of NSStrings allocations mentioned below

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.

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