Lazy instantiation in Objective-C/ iPhone development
Asked Answered
H

4

27

Quick question... Well I understand that all properties start out as nil in Objective-C and that sending a message to nil does nothing, therefore you must initialize using [[Class alloc] init]; before sending a message to a newly created property. However, what about if I'm not sending messages to this property or if I set the property using self.property = something? Do I need to alloc init in these cases as well? Also, do UI properties start out as nil as well, such as a UILabel property that you drag out from your storyboard? Do these need alloc init?

Thanks to all who answer

Histrionics answered 2/8, 2012 at 0:44 Comment(1)
+1 very good question. Sending messages to not-yet-alloc/init property is a common mistake for OjbC beginners.Francis
O
41

Stunner did a good job of explaining not needing to alloc init objects that have already been created.

But if it is an object that doesn't exist, where are you going to create it? A very common pattern, which I mention because you mentioned it in your post, is lazy instantiation.

So you want an NSMutableArray property. You could alloc init it in some method before you use it, but then you have to worry about "does that method get called before I need my array?" or "am I going to call it again accidentally and re-initialize it."

So a failsafe place to do it is in the property's getter. It gets called every time you access the property.

.h
@property (nonatomic, strong) NSMutableArray* myArray;

.m
@synthesize myArray = _myArray;

- (NSMutableArray*)myArray
{
    if (!_myArray) {
        _myArray = [[NSMutableArray alloc] initWithCapacity:2];
    }
    return _myArray;
}

Every time you access that property, it says, "Does myArray exist? If not, create it. If it does, just return what I have."

Plus an added benefit with this design pattern is you aren't creating resources until you need them, versus creating them all at once, say, when your view controller loads or your app launches, which, depending on the requirements, could take a couple seconds.

Oswell answered 2/8, 2012 at 2:34 Comment(2)
Good response, but I would disagree with instantiating ivars in getters as that makes querying for existence of the object infeasible. Rather, I would recommend you do the instantiation in the setter because you know for sure if that ivar that you are setting does not exist, you want it to exist so that it can be set to a value. Hence, there would never be a time where you wouldn't want it to exist when calling a setter, whereas when calling a getter, that is not always the case.Allegorist
If I can add to this so late... would you need to add it in the setter if the property has the 'copy' attribute since it would already get a copy to use?Gt
L
4

The reality is when you do self.myProperty = [[Class alloc] init], you're not initializing your property. Rather, you're initializing an object that you tell your property (which is in fact a pointer) to point to. So if you already have an object that's allocated and initialized, you don't have to alloc/init again and you can do self.myProperty = object;

UI Properties do no start as nil, this is because when you add elements in the interface builder, the view owns the elements that you add and these objects are initialized automatically for you. This means if you're creating IBOutlets and connecting them to some properties, you don't have to alloc/init.

I hope this was helpful.

Lustful answered 2/8, 2012 at 0:52 Comment(0)
A
1

I don't have experience with Storyboards but I know that when you create objects via a xib file all objects are properly instantiated when you tell a view controller to use a xib file. So you need not worry about alloc/initing those objects in code.

Regarding using self.property = <something>, it depends on what something is. If something is any sort of existing object you need not do the alloc init on that object as the self.property = ... syntax calls the property's setter method which will retain, copy, assign, etc. the new value to the property appropriately.

Now any sort of existing object can be an alloc/init'ed object, or an autoreleased object obtained from a convenience method (NSString's stringWithFormat: for example).

As Kaan Dedeoglu pointed out, the self.property = ... syntax points (and retains) the ivar to the object in memory, and it is up to you to initialize that object if it isn't already instantiated.

Allegorist answered 2/8, 2012 at 1:1 Comment(0)
T
0

No you do not need to [[Class alloc]init the properties in your init method.

However, I would encourage you to explicitly set them to Nil in your init method for clarity.

Tat answered 2/8, 2012 at 0:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.