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

  • In init, and only when they need it. They're all initialized to nil, which is a perfectly reasonable value for an instvar to have; there's very rarely a reason to do anything like

    > name = [NSString string];

    because sending a method to nil is perfectly safe, unlike C++.

    > foodLists = [NSMutableArray array];

    is necessary, as you've seen, but not for the reasons you think.

    > it crashes.

    Somewhere else, I assume? It's not going to crash on that line; is something expecting to get "foo" back out of your object? That's not going to happen because there's nothing hanging on to it; "[m1.foodLists addObject:foo" is a no-op when foodLists is nil.

    Declaring that foodLists is an NSMutableArray doesn't mean that there will be an NSMutableArray there, just that you're telling the compiler you're going to use it to store one.

    ----- Original Message -----
    From: "fly2never" <fly2never...>
    To: <Cocoa-dev...>
    Sent: Sunday, June 24, 2012 10:48:36 PM
    Subject: 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 18.07.2012, at 09:09, Lee Ann Rucker wrote:
    > In init, and only when they need it. They're all initialized to nil, which is a perfectly reasonable value for an instvar to have; there's very rarely a reason to do anything like
    >
    > fly2never wrote:
    >> name = [NSString string];
    >
    > because sending a method to nil is perfectly safe, unlike C++.

    Ah! No! That's not a blanket guarantee! It is only valid for methods that return void, integer types or pointers. If your method returns a struct and you send it to NIL, you get garbage back.

    >> it crashes.

    If you are not using ARC, I could see why the first code sample crashes ([NSString string] returns an object you do not own -- either retain it, or use [[NSString alloc] init] instead, otherwise it gets released and your instance variable contains the address of an object that is long gone, and you'll crash when you next try talking to it).

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

    In general, I would recommend sticking with initializing everything in -init unless you have a good reason (e.g. if you need to refer to an external object that also needs to know about your object, you have to create one first, before you can have the other one reference it, so obviously you can't do that until -init has returned). But premature optimization is the root of all evil. So better set up everything so you're sure it's correct.

    That's one major advantage of objects: They encapsulate their own behavior, so people who actually use them don't have to know about their internal workings too much. The object just "does the right thing" by default, and you only change the values that you need differently.

    Similarly, as others have written, don't just give the client of your object your mutable array. Give them methods to add to and remove objects. That way, your object can actually know whether someone just looked at your objects, or changed them. You may have an internal cache later, and when someone changes the array, you have to know about it so you can remove a deleted object from the cache etc.

    Cheers,
    -- Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.masters-of-the-void.com
  • On 18 Jul 2012, at 08:09, Lee Ann Rucker wrote:

    > In init, and only when they need it. They're all initialized to nil, which is a perfectly reasonable value for an instvar to have; there's very rarely a reason to do anything like
    >
    >> name = [NSString string];
    >
    > because sending a method to nil is perfectly safe, unlike C++.
    >
    >> foodLists = [NSMutableArray array];
    >
    > is necessary, as you've seen, but not for the reasons you think.

    Both of those lines are going to cause random crashes later on because they're non-retained objects.

    Chris
  • Le 18 juil. 2012 à 15:03, Chris Ridd <chrisridd...> a écrit :

    >
    > On 18 Jul 2012, at 08:09, Lee Ann Rucker wrote:
    >
    >> In init, and only when they need it. They're all initialized to nil, which is a perfectly reasonable value for an instvar to have; there's very rarely a reason to do anything like
    >>
    >>> name = [NSString string];
    >>
    >> because sending a method to nil is perfectly safe, unlike C++.
    >>
    >>> foodLists = [NSMutableArray array];
    >>
    >> is necessary, as you've seen, but not for the reasons you think.
    >
    > Both of those lines are going to cause random crashes later on because they're non-retained objects.
    >

    They are perfectly valid lines in the new ARC world.

    -- Jean-Daniel
  • On Jul 18, 2012, at 1:27 AM, Uli Kusterer <witness.of.teachtext...> wrote:

    > On 18.07.2012, at 09:09, Lee Ann Rucker wrote:
    >> In init, and only when they need it. They're all initialized to nil, which is a perfectly reasonable value for an instvar to have; there's very rarely a reason to do anything like
    >>
    >> fly2never wrote:
    >>> name = [NSString string];
    >>
    >> because sending a method to nil is perfectly safe, unlike C++.
    >
    > Ah! No! That's not a blanket guarantee! It is only valid for methods that return void, integer types or pointers. If your method returns a struct and you send it to NIL, you get garbage back.

    The restrictions have gotten a lot less severe lately: http://developer.apple.com/library/ios/documentation/cocoa/conceptual/objec
    tivec/Chapters/ocObjectsClasses.html
    (see "Sending Messages to Nil")

    Floating-point-returning message to nil has been safe since 10.5, I believe.

    As of 10.7, struct-returning message to nil is also nil-safe if the return value fits in registers.

    --Kyle Sluder
previous month july 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 31          
Go to today