Ive been coding for about 2 years now and i recently understood something which has helped me a great deal so i wanted to share it with you.  First let me just expose my learning path so you can determine if its comparable to yours and decide if this article may be of help or just good for a few laughs 🙂

 

Little HS and College programming background.  Biochem (heavy math and science background).  Picked up HTML and ASP on my own with books and online sites.  Did that for about 4 years.  Picked up iOS at 3.0 and started out using stanfords free online course and made a couple of apps, Paparrazi and Presence.  Also went thru online courses including Apple’s Documentation.  However i was overwhelmed my Apple Docs and online tutorials each took different approaches so i got confused.  Started looking at Apple Apps which are free and picked up some coding ideas.  However, all this time ive been missing one of the most important fundamentals, Memory Management.  I read Apple Docs as well as many others online but twas this Apple Dev Post that really brought the point home for me.

I am working on an app with tableviews and quite a few NSObjects.  My app was crashing left and right.  It did things right, but crashed at unexpected times.  Leaks Instruments is too obscure for me, im still trying to find a good video explaining how leaks actually points you to the leak! (for a newbie…not for an amateur or pro).

So i posted this in the DevForums:

I was trying to pass an object from one Class to another.  This was the receiving class declaring and ivar-property for the object to be received.

——-I create an ivar in some Class & synthesize it later.  Then in a method i do this:————————————-

MyObject *newObject;    //ivar and make it a property with

@property (nonatomic, retain) MyObject *newObject

newObject.userName = localvariable;

Do i need to release it since i didnt user alloc/init.  But im thinking that it does go to the MyObject Class and create it in order to be filled here, so since i did a (retain) in the property interface, i may have to do a release…right?

——–Then there was some back and forth, so i decided to post my code—————————————————

Allow me to paste some code and interpret it for your correction:

-(void) viewDidLoad{
     // This is not an ivar nor a property
     NSDictionary *anEntry;
     // This is not an ivar nor a property
     NSArray* userDictArray = [HelperClass fetchUsers];
     // This is an ivar and property
     usersArray = [NSMutableArray arrayWithCapacity:[userDictArray count]];
     // I need to cycle thru the userDictArray and create the usersArray
     for (anEntry in userDictArray){
          [usersArray addObject:[anEntry objectForKey:@"name"]];
          // [usersArray retain];  this was commented out because it shouldnt be retained in the loop
          // it really shouldnt need to be retained right?  
     }

     // This is not an ivar nor a property
     // This is just an NSObject Class created specifically for this step
     Users *nsUsers = nil;
     for (int count = 0; count<[masterArray count]; count++){
          nsUsers = [masterArray objectAtIndex:count];
          [usersArray addObject:nsUsers];
          [nsUsers release];  //This is the proper place to release it because its been added to the array already
     }

a) NSDictionary anEntry does not need to be released because i dont alloc/init it…

You don’t create an object at all – it is nil. All you are doing is declaring a local pointer variable.

b) userDictArray im unsure because this is not really a convenience method, so what does it depend on whether its released or not?

If you wrote the “fetchUsers” method, then it should have returned an autoreleased object. But that responsibility is on the fetchUsers method. In your current method you should assume that the userDictArray is not owned by you, and retain it if you need it to stay around. However, note that the pointer to it is a local variable to this method “viewDidLoad” so that after the method completes, the pointer will disappear. Thus if you retain the object, there will be no way to release it later (because nothing has a pointer to it) and it will leak.

c) usersArray is a property created with a convenience method as well, which is why i originally inserted the [usersArray retain]; because i didnt want the program to crash, but i believe it would need to go outside the loop.  Therefore it should be released retained outside the loop and then released in dealloc?

usersArray already has the retain attribute, correct? Then just use self.usersArray when assigning the arrayWithCapacity to it and the setter method will do the retain. Note that this is NOT a local variable (it is an instance variable), so it will be available for the life of the instance (the view controller).

d) nsUsers needs to be released?  Its not really a convenience method used to fill it in, so again, what does it depend on?

You never even created an object, so there is nothing to release. All you did was 1) declare a pointer and 2) assign a value to that pointer.

Users *nsUsers=nil; // <- all this does is declare a C variable that will be a pointer variable to an object of the “Users” class. No object is created. Since the pointer is nil, it is not pointing to anything.  Setting a pointer to nil does not “blank out” anything. There is no concept of “blanking out” in computer science. Use that concept to show that setting the pointer to nil means that the pointer no longer points to anything, and thus cannot be used to send messages to the object, including the “release” message.

//READ THIS CAREFULLY:

nsUsers = [masterArray objectAtIndex:count]; //<- all this does is fill in the “nsUsers” pointer with the pointer to the object at the index specified. No object is transferred – only the pointer is placed in the C pointer variable “nsUsers”.

The expression “[masterArray objectAtIndex:count]” returns a pointer to that object specified. The C variable “nsUsers” is set to contain that pointer. That is all. So now, the C pointer variable “nsUsers” can be used to send messages to the object that it is pointing to. That’s all.

 

1.  Everything is an object.  In ObjC everything is an object.  Don forget that when you declare an ivar in the interface thats just a pointer.  If you make it into a property you basically converted it into an object and should use setters [object setProperty:value]; because if you say property = value you are not using the property, you are using the ivar.

2.  You dont talk to objects, you talk to their pointers.  In order to talk to objects you need a channel, a rope and can, a hose if you will.  Those are called pointers.  You never talk to objects directly.

3.  Pointers point, variables ARE!…Pointers only point to where the object is.  Once you have them, thats how you tell an object to do this or that, change its property values etc.  The cool thing then about pointers is that you can use them to alter a result without changing the actual value.  I know, this sounds like an typical explanation…well here is an example 🙂

Think about this code:

// this is a helper function
void increment(int x)
{
    x = x + 1; // cool because you could do stuff with x (now = 7) without affecting myValue (6)
}
// this is the main function
int myValue = 6;
increment(myValue);
NSLog(@"%d:\n", myValue);

You see, the helper function just took the value of myValue (6), increased it by one & threw it away.

//[6]
void increment(int *y)  // received the address to myValue, the address to 6
{
    *y = *y + 1;  //modifies the address to myValue by adding 1 to it, wherever it is...
}
// this is the main function
int myValue = 6;
increment(&myValue); // passing the address to myValue, not the number 6

4.  Dont lose your pointers…If you declare ivars (pointers) in your interface, and make them properties which u later synthesize, AND u set them as self.myProperty = someValue, then they will be available for the entire life of the instance your class creates.  If you simply declare them locally in some method by saying NSString *myString then they will only be available in that block of code (if else, switch) or in that method.  So any object you create in here, must be released in here.  If you pass its pointer to another method, your original pointer will be destroyed when the method ends and the object will leak.

5.  Alloc/init/copy/retain/setFoo…RELEASE!  foo = bar; means set foo pointer to point to bar.  You are only changing where the pointer points.  NOT THE VALUE ITSELF.  Thats what ivars do.  [self setFoo:bar] or self.foo = bar; actually calls the setter method and changes the value.

6.  Use Properties, not ivars…unless ur in dealloc.  Ivars are in essence the same as properties except that properties are objects with setters.  Whereas ivars are simply pointers.  So you can user ivars for temporary stuff; pointing to things.  But if you make it into a property you have to use setFoo, which calls a method.  These properties are available anywhere in your class (during the instance)

One Comment

Leave a Reply