Why aren't these NSString instance variables allocated? - ios

first post here. I was reading through an Objective-C tutorial earlier, and I saw that they had made a couple of NSString instance variables like this:
#implementation MyViewController {
NSString *stringOne;
NSString *stringTwo;
NSString *stringThree;
NSString *stringFour;
NSString *stringFive;
}
And then simply used them in ViewDidLoad like this:
- (void)viewDidLoad
{
[super viewDidLoad];
stringOne = #"Hello.";
stringTwo = #"Goodbye.";
stringThree = #"Can't think of anything else to say.";
stringFour = #"Help...";
stringFive = #"Pheww, done.";
}
How have they done this without instantiating the string? Why does this work? Surely you'd have to do something like stringOne = [NSString stringFromString:#"Hello."]; to properly alloc and init the object before you could simply do stringOne= #"Hello.";.
Sorry if this a dumb question, but I find these little things throw me.
Thanks,
Mike

From the Apple String Programming Guide:
Creating Strings
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"Contrafibularity";
Note that, when creating a string constant in this fashion, you should use UTF-8 characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated. You can also send messages directly to a string constant as you do any other string:
BOOL same = [#"comparison" isEqualToString:myString];

String constants like #"Hello" are already allocated and initialized for you by the compiler.

Just remember this basic thing:-
NSString *string = ...
This is a pointer to an object, "not an object"!
Therefore, the statement: NSString *string = #"Hello"; assigns the address of #"Hello" object to the pointer string.
#"Hello" is interpreted as a constant string by the compiler and the compiler itself allocates the memory for it.
Similarly, the statement
NSObject *myObject = somethingElse;
assigns the address of somethingElse to pointer myObject, and that somethingElse should already be allocated and initialised.
Therefore, the statement: NSObject *myObject = [[NSObject alloc] init]; allocates and initializes a NSObject object at a particular memory location and assigns its address to myObject.
Hence, myObject contains address of an object in memory, for ex: 0x4324234.
Just see that we are not writing "Hello" but #"Hello", this # symbol before the string literal tells the compiler that this is an object and it returns the address.
I hope this would answer your question and clear your doubts. :)

actually this can be said "syntactic sugar". there are some other type of NS object that can be creatable without allocation or formatting.
e.g:
NSNumber *intNumber1 = #42;
NSNumber *intNumber2 = [NSNumber numberWithInt:42];
NSNumber *doubleNumber1 = #3.1415926;
NSNumber *doubleNumber2 = [NSNumber numberWithDouble:3.1415926];
NSNumber *charNumber1 = #'A';
NSNumber *charNumber2 = [NSNumber numberWithChar:'A'];
NSNumber *boolNumber1 = #YES;
NSNumber *boolNumber2 = [NSNumber numberWithBool:YES];
NSNumber *unsignedIntNumber1 = #256u;
NSNumber *unsignedIntNumber2 = [NSNumber numberWithUnsignedInt:256u];
NSNumber *floatNumber1 = #2.718f;
NSNumber *floatNumber2 = [NSNumber numberWithFloat:2.718f];
// an array with string and number literals
NSArray *array1 = #[#"foo", #42, #"bar", #3.14];
// and the old way
NSArray *array2 = [NSArray arrayWithObjects:#"foo",
[NSNumber numberWithInt:42],
#"bar",
[NSNumber numberWithDouble:3.14],
nil];
// a dictionary literal
NSDictionary *dictionary1 = #{ #1: #"red", #2: #"green", #3: #"blue" };
// old style
NSDictionary *dictionary2 = [NSDictionary dictionaryWithObjectsAndKeys:#"red", #1,
#"green", #2,
#"blue", #3,
nil];
for more information, see "Something wonderful: new Objective-C literal syntax".

Related

What is the difference between #"1.5" and #(1.5) while setting the value in NSDictionary?

In iPhone project,
It was while I was while setting Value in dictionary,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];
AND,
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];
My question is Why not #"2.5" and #(2.5) ?
You have two questions, it would be better to have a single question.
But as to the difference,#"2.5" is an NSString where #(2.5) is an NSNumber. There is a big difference between textual and numeric data.
As for why you need an NSNumber and not NSString is obvious: the kerning is a numeric value.
using the #() syntax you can box arbitrary C expressions. This makes it trivial to turn basic arithmetic calculations into NSNumber objects see below:
double x = 24.0;
NSNumber *result = #(x * .15);
NSLog(#"%.2f", [result doubleValue]);
You can also refer NSNumber object as #"" string but cant make calculations like above example. In your case both are acceptable but here calculation makes difference.
When you use
#"2.5" it's behave like a string
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#"2.8" forKey:#"Why"];;
NSString *a = [dictionary ValueforKey:#"Why"];
but when you use #(2.8) then it's behave like a NSNumber
NSMutableDictionary*dictionary=[[NSMutableDictionary alloc] init];
[dictionary setValue:#(2.8) forKey:#"Why"];;
NSNumber *a = [dictionary ValueforKey:#"Why"];
#(2.8) is a type of NSNumber.
#"2.8" is a type of NSString.
Both the type and value were different between there two.

iOS—NSDictionary has 6 keys, shows 3

For a task tracking app, I'm using an array of NSDictionaries that contain certain details about the task—-duration, etc.
NSString *savedTaskName = addedTask.taskName;
NSString *savedTaskAccountName = addedTask.accountName;
NSString *savedTaskBillCode = addedTask.billCode;
NSString *savedTaskActivityCode = addedTask.activityCode;
NSNumber *savedTaskDuration = [NSNumber numberWithFloat:addedTask.taskDuration];
NSString *savedTaskTimeCode = addedTask.formattedTimeString;
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
savedTaskActivityCode, kActivityCode,
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
Perhaps I'm making a newb mistake, but when I go to add addedTaskData to an NSMutableArray, the array only catches the first three values and keys of the dictionary.
Have I lost my mind? Why isn't it catching all? Curiously, asking for the count of dictionary keys returns the full amount.
initWithObjectsAndKeys stops when it hits a nil value. If you're getting three keys/values, then:
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
savedTaskActivityCode, kActivityCode, // <-- THIS IS NIL
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
You can use something like this instead:
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
(savedTaskActivityCode ?: [NSNull null]), kActivityCode, // Or #""
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
Anything that could be nil should be protected like this.
If you're doing a bunch of them in a row, you can declare a local null variable:
id null = [NSNull null];
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:(savedTaskName ?: null), kTaskName,
(savedTaskAccountName ?: null), kAccountName,
(savedTaskBillCode ?: null), kBillCode,
(savedTaskActivityCode ?: null), kActivityCode, // Or #""
(savedTaskDuration ?: null), kTaskDuration,
(savedTaskTimeCode ?: null), kTimeCode, nil];
When not using the literal syntax there is a chance that you will run into nil termination issues. If savedTaskDuration is actually nil then it's going to chop off the rest of the NSDictionary.
Take a look with the debugger and see if you have a nil value in there somewhere. Then run the Modern Objective-C refactor tool and convert that sucker to a NSDictionary literal so that you are protected from this in the future.
For reference the Literal syntax is like this:
NSDictionary *addedTaskData = #{#"Key" : #"Value", #"AnotherKey" : #"AnotherValue"};
Try to use literals like this:
NSString *savedTaskName = addedTask.taskName;
NSString *savedTaskAccountName = addedTask.accountName;
NSString *savedTaskBillCode = addedTask.billCode;
NSString *savedTaskActivityCode = addedTask.activityCode;
NSNumber *savedTaskDuration = [NSNumber numberWithFloat:addedTask.taskDuration];
NSString *savedTaskTimeCode = addedTask.formattedTimeString;
// Use literals and see your code doesn't crash
NSDictionary *addedTaskData = #{kTaskName: savedTaskName,
kAccountName: savedTaskAccountName,
savedTaskBillCode: savedTaskBillCode,
savedTaskActivityCode: savedTaskActivityCode
savedTaskDuration: savedTaskDuration
savedTaskTimeCode: savedTaskTimeCode};
And see your code doesn't crash

Adding NSString to NSMutableString

I want to add multiple NSStrings yo an NSMutableString to construct a list of strings.
This is my code in a method that takes an NSDictionary and grabs the value out of it - it then stores it in an NSString, From there I append the string to the NSMutableString. When running this method for the first time it works. However, when I call the method again, it replaces the last string that was in the NSMutableString.
Here is the code:
NSString *userId = [NSString stringWithFormat:#"%#,", parameters[#"userId"]];
self.alluserIds = [NSMutableString string];
[self.alluserIds appendString:userId];
Can anyone tell me what I am doing wrong?
self.alluserIds is declared strong.
This:
self.alluserIds = [NSMutableString string];
is creating a new mutable string. It should be done once, before you want to use the mutable string, and not done again until you want to restart (because recreating the mutable string destroys the old instance you had).
This is happened because you call:
self.alluserIds = [NSMutableString string];
This create new string and assign it to self.alluserIds. You should call it just once in for example init method or viewDidLoad.
You should initialize with the string you are using and it should be a single initialization your code should look like below.
NSString *userId = [NSString stringWithFormat:#"%#,", parameters[#"userId"]];
if(!self.alluseIds)
self.alluserIds = [[NSMutableString alloc] initWithString:userId]; //ONLY Initialization
else
[self.alluserIds appendString:userId];
Hope this helps
I don't know your data-structure, but if you might have all userids in an array you could join them together with componentsJoinedByString::
NSArray *pathArray = [NSArray arrayWithObjects:#"here", #"be", #"dragons", nil];
NSLog(#"%#",[pathArray componentsJoinedByString:#" "]);
Don't use mutable strings(and mutable collections too) except cases you really need it: http://rypress.com/tutorials/objective-c/data-types/nsstring.html (When To Use Mutable Strings) You have to use them when you want to make a lot of operations. Immutable collections are slower because you create new instance when append another string.
How to do this with NSString:
self.alluserIds = [self.alluserIds stringByAppendingString: userId];

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.

How to better initialize strings to avoid dead stores

I found a few questions like this but I couldn't find this particular question. I have a number of strings that are initialized as
NSString *string = [[NSString alloc] init];
which are then assigned a value depending on the results of an if/else block:
if ([anotherThing isEqualToString:#"boogers"]) {
string = [NSString stringWithFormat:#"some characters"];
} else {
string = [NSString stringWithFormat:#"some _other_ characters"];
}
and then string is used later in the method.
How can I accomplish this without leaving a dead store at the alloc/init stage? If I alloc inside the if (or the else), the string is gone by the time I need it several lines down.
You don't have to initialize the string on that first line -- you just need to declare it:
NSString *string = nil;
if ([anotherThing isEqualToString:#"boogers"]) {
string = #"some characters";
} else {
string = #"some _other_ characters";
}
The [NSString stringWithFormat:] will initialize a new NSString object for you, basically what you are doing is declaring a new object each time, just set the pointers for your strings as NSSTring *someString, *someOtherString, *allTheStringsYouNeed; and then use any class method to initialize it even #"Characters"; will work correctly as the compiler do it at runtime for you.

Resources