When to Alloc/Init NSArray?

Discussion in 'iOS Programming' started by AxoNeuron, Aug 5, 2014.

  1. AxoNeuron macrumors 65816

    AxoNeuron

    Joined:
    Apr 22, 2012
    Location:
    The Left Coast
    #1
    I have always been unsure of when and how I should allocate and initialize an NSArray or NSMutableArray. For example, if I have an NSMutableArray object property, I should use lazy instantiation for it should I not?

    What about NSUserDefaults? It seems to work even if I don't Alloc/Init it. Is there some place I can get this very simple information? Apple's documentation on these classes don't seem to say, I'm sure they assume you already know such basic information :)
     
  2. ChristianJapan, Aug 5, 2014
    Last edited: Aug 5, 2014

    ChristianJapan macrumors 601

    ChristianJapan

    Joined:
    May 10, 2010
    Location:
    日本
    #2
    Yes, you need to create an instance of the array. If not you can't add any object to it.


    Code:
    NSMutableArray *list;
    
    [ list addObject:foo]; 
    Will technicall work, but not doing what is intended as no array is created. Only a reference to an array with NULL as value.

    Code:
    NSMutableArray *list;
    list = [ [ NSMutableArray alloc] init];
    [ list addObject:foo];
    Here we create a real list and can assign real entries. Note: maybe better to use the convinience methods like [NSMutableArray arrayWithCapacity:5]; which I preferr.

    NSUserDefaults is doing that for you. Via its methods it delivers you an instance of an Array with the desired content.

    Try this in debugger:
    Code:
    NSMutableArray *list;
    
    [ list addObject:foo];      // will do nothing as no list got created
    
    list = [ [ NSMutableArray alloc] init];
    [ list addObject:foo];    // one object added to list
    
    
    And watch what happen with list.
     
  3. grandM macrumors 6502a

    grandM

    Joined:
    Oct 14, 2013
    #3
    In my opinion it's preferred to use lazy instantiation when you're using an instance of the object in several places. Meaning if you declare it in the public or private interface. If you only need the mutable array locally inside a method you could declare, allocate and initialize it there.

    NSUserdefaults is active over several apps. Allocation and so on is done by the OS.
     
  4. ChristianJapan macrumors 601

    ChristianJapan

    Joined:
    May 10, 2010
    Location:
    日本
    #4
    Looks like I slightly misunstood the question before my first cup of tea ....

    So I would like to add: yes, lazy init on the property and checking if not already done before sometimes/somewhere else

    If (_list == Null)
    {
    ... Do the init here
    }
     
  5. PBG4 Dude macrumors 68000

    PBG4 Dude

    Joined:
    Jul 6, 2007
    #5
    The easiest place would be in the getter method. Just do

    Code:
    
    @property (nonatomic, strong) NSMutableArray   *myMutableArray;
    
    
    ...
    
    - (NSMutableArray)myMutableArray {
         if (!_myMutableArray) {
              _myMutableArray = [[NSMutableArray alloc] init];
         }
    
         return _myMutableArray;
    }
    
     
  6. Menge macrumors 6502a

    Menge

    Joined:
    Dec 22, 2008
    Location:
    Amsterdam
    #6
    Actually, that code might not work. Only iVars are initialized to nil. If you do NSMutableArray *list; inside a function, it is a garbage pointer. It might be nil. But it might point to unowned memory and cause a segfault when you do [list addObject:foo] on it.

    Don't forget that that implementation is not thread-safe. If you happen to call something.myMutableArray on two threads simultaneously, you will get a race condition and leak memory.
     
  7. grandM, Aug 6, 2014
    Last edited: Aug 6, 2014

    grandM macrumors 6502a

    grandM

    Joined:
    Oct 14, 2013
    #7
    Of course, or
    1 declare in interface-end, do lazy instantiation and inside the method use [self.list addObject:foo] hence using the getter, list being myMutableArray
    or
    2 everything in the method
    NSMutableArray *list = [[NSMutableArray alloc] init];;
    [ list addObject:foo];

    I wonder in the 2nd case would there be a problem if list were already allocated and instantiated globally
     
  8. PBG4 Dude macrumors 68000

    PBG4 Dude

    Joined:
    Jul 6, 2007
    #8
    If list had items in the array, your alloc/init would remove them from the list. That's why you'll need an if statement to check if list already exists before doing an alloc/init.
     
  9. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #9
    Doesn't the default getter already do pretty much the same thing?
     
  10. grandM macrumors 6502a

    grandM

    Joined:
    Oct 14, 2013
    #10
    So the NSMutableArray *list = [[NSMutableArray alloc]init] will make the pointer to the array shift from for instance 36 to 752. Is this also the case with different scopes: list could be inside a method while self.list continues to exist?
     
  11. PBG4 Dude macrumors 68000

    PBG4 Dude

    Joined:
    Jul 6, 2007
    #11
    The default getter will not alloc/init an object. It will just return nil if he object is nil.
     
  12. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #12
    Ah, that's right. Thanks for setting me straight.
     

Share This Page