When to use alloc init in objective-c - objective-c

Hey guys I just have a simple objective c question, I have been looking over my companies code base and I have stumbled upon something interesting. When should you use [[alloc] init] and when should you not. Here is a classic example:
Case 1:
NSString *url = nil;
url = #"hi";
Case 2:
NSString *url = [[NSString alloc] init];
url = #"hi";
So when should you use Case 1 and when should you use Case 2? I am hoping someone can settle this for me once and for all, throughout my app development I have been using Case 2 because I thought it was equivalent to calling a "new" in C++ (basically invoking an objects constructor). I am shocked that Case 1 even works, because Case 1 indicates no invokation of a constructor or memory allocation for that object. Case 1 is used everywhere in the code base I am looking at though.

alloc creates storage and does some basic automatic setup, returning an instance of the class. init allows the instance to configure itself as per the logic required for that class. = assigns a different instance to the pointer.
So the first is always correct, the second always incorrect. There's no point creating an instance of an object then throwing it away one line later.
(aside: with ARC you can always skip the = nil as it's implied; in your case you could skip it regardless because of the following assignment)

#"hi" creates an instance of NSString. It does the allocation and initialization. Therefore, in case 2, you are pointlessly allocating memory and then reassigning the "url" pointer to a new piece of memory.
You have to remember that "url" is a pointer. Just like in C or C++, when you use the "=" operator you are reassigning where it is pointing, you are not affecting the memory it used to be pointing at. In C, if you want to change the value stored at the newly allocated memory, you would have to use the dereference operator.

alloc creates an object. So you use it when you want to create an instance of a class. In this case, you do not want to create an object, because you're going to assign the existing object #"hi" to the variable. So you would never write Case 2, as it creates an object and immediately discards it for another object.

Related

Objects with the same name, what does that mean?

I thought I had a decent understanding of objects, but I guess not. What happens when two objects are the same name? They are both pointing to the same location in memory? So if I had one class that said:
SomeClass *someObject = [SomeClass new];
someObject.text = #"test";
And another class instantiates the same object with the same name:
SomeClass *someObject = [SomeClass new];
someObject.textColor = [UIColor redColor];
This would modify the same object to be a red text that says "test" right ?
Thanks!
~Carpetfizz
No, those two pointers point to two different objects in the memory. It doesn't matter if they have the same name. They were allocated and initialized separately in two different classes.
Btw, you should never use the new method to allocate and initalize the object. The new message is discouraged, as allocation and initialization are two different processes. You should use this instead:
SomeClass *someObject = [[SomeClass alloc] init];
Nope. Just because two variables happen to share the same name does not mean they share the same memory location. When this compiles, the compiler strips the variable names (but not the class names) and calculates memory offsets and messages instead of names and classes. Besides, as a local variable, as soon as they pass out of scope -most likely at the end of each function that created them- they will be destroyed immediately.
No. You can't do that.
Any modern-day compiler will attempt to strangle you before compiling that code - for that exact reason: It doesn't know what to do!
Even if you could get the compiler to make it work, just because the two objects have the same name doesn't mean they have the same memory address.

When and when to not allocate memory to objects

NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.

Using objects I didn't allocate or initialize

I just wrote some code. It has my own custom made class. In that custom made class called 'WonderfulNumbers' I have a method that looks like this
- (NSString *)storedNumberAsString {
NSString *stringToReturn = [[NSString alloc]initWithFormat:#"Hello World"];
return [stringToReturn autorelease];
}
I obviously then #import "WonderfulNumbers" into the main and etc
then in my main I have an IBAction.
it reads like the following
-(IBAction)displaySomeText:(id)sender {
WonderfulNumbers *myNumber = [[WonderfulNumbers alloc]init];// Step 1
NSString *numberString = [myNumber storedNumberAsString];// Step 2
[textView insertText:numberString];// Step 3
//textView is a variable of NSTextView.
[myNumber release];// Step 4
}
I get the step by step process, and the logic behind this.
What I like to know and try to reassure to my self is what exactly is happening at step 2.
I understand Step 1, 3 and 4.
But step 2, I crated an NSString variable called 'numberString' and it obviously holds the object called 'myNumber' with the method described above applied to it. Makes sense.
What I want to know is, I never allocated or initialized the 'numberString' object of NSString class. How am I able to then use it.
I know I don't release it since it's never allocated .. but did I initialize it by just doing [myNumber storedNumberAsString]; ?
A slight explanation would be awesome. Thank's to those that reply.
P.S. I know that everything in objective-c is an object but just for the sake of this argument, since 'numberString' is not technically "created by allocate and init" is it right to call that a variable?
I think I know the differences between the two but just want reassurance.
Thanks.
You are initializing NSString *stringToReturn to the return value of [myNumber storedNumberAsString]. Inside storedNumberAsString you can see that it returns an NSString reference, properly allocated and all, so it's fine to use.
The key here is autorelease, which causes the object to be released automatically “sometime later” (actually when the topmost autorelease pool is released, which, unless you changed it yourself, tends to happen after each iteration of the event loop).
The convention in Objective-C is that if you alloc or retain an object, or get an object from a method whose name begins with new, copy, or mutableCopy, you are responsible for releasing it. Otherwise you can assume it will be released by someone else (e.g., later via autorelease). Since storedNumberAsString does not begin with new, copy, or mutableCopy, you don't need to release it. Meanwhile the implementation of storedNumberAsString must ensure that the object it allocs gets released -- in this case that is done by calling autorelease on it.

Assigning object pointers

Is this pointer assignment correct?
customclass.somearray = &*otherarray;
where somearray and otherarray are NSArray objects.
If not, how do I solve my problem:
I want to share this otherarray object with customclass.somearray. And I want all changes
made to customclass.somearray to be made to the original otherarray too.
Doing it this way, it works. I just want to ask, is it correct?
Your two variables are pointers of the same type, so just assign one to the other:
customclass.somearray = otherarray;
The way you have written this is unnecessary. Using the dereference operator * essentially gives you the "contents" of the pointer. The address-of operator & correspondingly gives you the address of whatever you apply it to. Your pointer otherarray contains an address. If you dereference that address and then take the address of that, you end up right back where you started.
Be aware that the left side of this assignment is a property access (assuming that customclass is also an object and not just a struct). This means that the compiler will change your expression into:
[customclass setSomearray:&*otherarray];
// And my version will be changed into:
[customclass setSomearray:otherarray];
That is, it becomes a method call rather than a simple assignment. This does not affect the syntax you should use, however.
When working in Objective-C, you never deal with objects directly, but always refer to them via pointers. Always. In C++, you can declare an actual object on the stack, for example, but you never do that in Objective-C. So, if you have:
NSArray *otherArray = [NSArray arrayWithObjects:#"foo", #"bar", nil];
then otherArray is a pointer to an instance of NSArray. Likewise, your somearray property will be of type NSArray*, so the types will match and you can just assign one to the other:
customclass.somearray = otherarray;
Hope that helps.

Memory cleanup on returned array from static method (objective-c)

In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?