do you init your instance variables in init method or outside the class?

  • I have a class Monkey like this:
    @interface Monkey : NSObject
    {
      NSString *name;
      NSMutableArray *foodLists;
      NSString *id;
      int age;
    }

    @property blah blah.........

    my init method looks like this:
    Method 1
    - (id)init
    {
      if ((self = [super init])) {
        name = [NSString string];
        foodLists = [NSMutableArray array];
        id = [NSString string];
      }
      return nil;
    }

    So when I call Monkey *m1 = [[Monkey alloc] init];
    I can use it directly. [m1.foodLists addObject:foo]; and everything goes
    fine.

    But if my init method like this :
    Method 2
    - (id)init
    {
      if ((self = [super init])) {
        // do nothing, leave instance variables uninitialized.
      }
      return nil;
    }

    Then I call Monkey *m1 = [[Monkey alloc] init];
    and I call [m1.foodLists addObject:foo]; , it crashes.
    I must use m1.foodLists = [NSMutableArray array]; and [m1.foodLists
    addObject:foo];

    ===================================Besides this two way to init instance variables, which one is the best
    practice?
    Method 1 ensure that all instance variables(properties) are initialized and
    no crash happened, but I think it's redundantly and inconvenient.
    Because like id and name. [NSString string] means nothing, I often assign a
    new value from outside, but init NSMutableArray looks necessary.
    Method 2 make no guarantee. If you need instance variables(properties),
    init it first before you use.
    what's your choice? Comments welcome : )
  • On Jun 25, 2012, at 12:48 AM, fly2never wrote:

    > Then I call Monkey *m1 = [[Monkey alloc] init];
    > and I call [m1.foodLists addObject:foo]; , it crashes.

    That won’t crash, because all instance variables are automatically initialized to nil. Sending the addObject: message to a nil object won’t crash — but neither will it do what you want. Instead, it won’t do anything, and your ‘foo’ object won’t get added — probably not what you want.

    Also, I wouldn’t give the user direct access to your internal NSMutableArray and let them monkey with it directly. Instead, implement a to-many property backed by the NSMutableArray, with which the users of the class can interact instead of directly with the array.

    Charles
  • On 25/06/2012, at 3:48 PM, fly2never wrote:

    > Besides this two way to init instance variables, which one is the best
    > practice?

    Of course you initialize your instance variables in -init - THAT IS WHAT IT IS FOR!

    It's very bad practice to let code outside the object set up ivars, because those ivars are an implementation detail of the object and are of no business to anyone else.

    You are also not following correct memory management of the objects you assign to your ivars in the examples you give (though if you are using ARC that might be OK).

    You can assign ivars lazily under some circumstances if there's some advantage to do so, for example, if your object has an -addFoo: method, and internally it uses an NSMutableArray to store them, you can create the array then, if needed, rather than in init. But there's usually not a great reason to do that.

    The other thing your code is doing pretty incorrectly is exposing the internal storage of the class. You don't ask your object for a mutable array, then call -addObject: on that array. You declare a method on your class that adds the object and that can call -addObject on the internal mutable array (or anything else if it decides to change the way it stores things).

    --Graham
  • If you create a new instance of a class, all its instance variables are zero, so any pointers to objects like strings and arrays are zero as well, they are there but do not point to anything. The instantiation does not automatically create those objects as well for you, you are responsible.

    You do not need to create placeholders in the init like you do in method 1. You can wait until your code tries to access such a variable through a getter method and then check to see if it already exists. If not, you create it on the spot.

    Currently you probably use @property to define your properties and @synthesize to create the getter and setter methods for them. Leave that in place, but still create your own getter method, for example foodLists, and in here first ask if it already points to an array, if not, alloc and init an array and assign this ti the instance variable. Now in the rest of your code, whenever you want to do something, like adding an item to foodLists, you can call [[self foodLists] addObject:xxxx] and this will first go through your getter method which then will check if there is a valid array already. No crash, no pain...

    Just my thought...

    [[[Brainchild alloc] initWithName:@"Richard Altenburg"] saysBestRegards];

    Op 25 jun. 2012, om 07:48 heeft fly2never het volgende geschreven:

    > Besides this two way to init instance variables, which one is the best
    > practice?
    > Method 1 ensure that all instance variables(properties) are initialized and
    > no crash happened, but I think it's redundantly and inconvenient.
    > Because like id and name. [NSString string] means nothing, I often assign a
    > new value from outside, but init NSMutableArray looks necessary.
    > Method 2 make no guarantee. If you need instance variables(properties),
    > init it first before you use.
    > what's your choice?
previous month june 2012 next month
MTWTFSS
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
Go to today