override getter only needs @synthesize
Asked Answered
I

3

7

I want to ovveride getter for lazy instantiation and leave default setter.

Do I need @synthesize ?

Why ?

@interface Foo()
@property (strong, nonatomic) NSObject *bar;
@end

@implementation Foo
- (NSObject *)bar
{
    if(!_bar) _bar = [[NSObject alloc] init];
    return _bar;
}
@end

Update: I've changed variable and class name, because it was confusing. From Deck and card to Foo and bar.

Immunize answered 11/12, 2013 at 15:7 Comment(3)
What what you developing for? i.e iOS6, iOS7 etc Because in theory I think it is from iOS6 when using ARC you don't need the @synthesizeFrictional
forget about @synthesizeMissy
iOS7. You need @synthesize when you override both setter and getter. This example was from Stanford: Developing iOS7, lecture 2Immunize
T
16

No, you only need to explicitly synthesize (to get the synthesized ivar) if you explicitly implement all of the accessor methods (both getter and setter for readwrite properties, just the getter for readonly properties). You've written the getter for this readwrite property, but not the setter, so the ivar will still be synthesized for you. Thus, as your code stands, you do not need to explicitly @synthesize.

If you made this property readonly, then implementing a getter would prevent your ivar from being automatically synthesized. Likewise, since this is readwrite, if you implemented both the getter and the setter, that would require you to synthesize the ivar (if you wanted one).

Tortoise answered 11/12, 2013 at 15:11 Comment(1)
+1 In other words: If your code compiles, you are good. If you would need @synthesize, compiler would not allow you to use _cards ivar.Bibliogony
P
5

Don't use lazy initialization this way. A Deck is useless without cards and, thus, lazy initialization buys you nothing but an indeterminate consumption of CPU whenever the first call to that getter might be. Fortunately, simply creating a mutable array costs nothing (which is also a reason not to use lazy initialization).

As well, vending a mutable collection breaks encapsulation. A Deck should contain all the logic for determine what set of Cards it contains and in what order. By vending a mutable collection, an external bit of code can change that order behind the Deck's back.

Beyond that, what does it even mean to "set" a Deck's cards? Going that route seemingly pushes all logic related to maintaining the Deck outside of the Deck class, begging the question as to why the deck is nothing more than a plain old array in whatever class uses the deck.

Pyxis answered 11/12, 2013 at 15:24 Comment(8)
Some of your points are not perfectly valid. Performance, as you said, is irrelevant. Lazy getter for mutable property will ensure, that it cannot be nullified. For example self.cards = nil; [self.cards addObject:card]; works perfectly.Bibliogony
@iMartin that does not "work perfectly" unless arbitrarily losing state is OK. Getters that mutate state, even for lazy initialization, are bad design that will cause significant problems over time. Far better to have a resetState method that actually does what it says concretely.Pyxis
@iMartin Why would you expose the property as readwrite anyway? Such a property should be readonly and setCards: would throw a compiler error. Everything here sounds like bad design.Jenine
Another thing to consider is KVO compiance. The example in the question does not notify the value has changed, breaking KVO.Jenine
@LeoNatan Exactly; there is no encapsulation here and the "business logic" of managing a Deck isn't contained.Pyxis
You guys are messing multiple things together. I didn’t say anything about exposing mutable collections. It’s of course bad design. Did you notice self? I was talking about using that collection inside the class. At any place, you can accidentaly assign nil there and no mutation wil ever work after that. This is one the most used cases, where I use lazy initialization. It works perfectly. Then that readonly thing. What’s wrong with setting cards of a deck? It’s normal, so why do you mention it here?Bibliogony
To be clear, here’s what I consider good design. Expose readwrite immutable collection with mutation accessors as needed (KVO-compliant or not, your choise, your needs). In implementation, use mutable counterpart with this lazy init. Then I implement immutable getter to return a copy, setter to replace contents and other accessors as needed. … No, in fact I usually fall back to Core Data for such things ;)Bibliogony
Defending against "accidentally assigning nil" is a bit of a waste. "OOops, I accidentally assigned nil and lost the collection full of all the game state. But, no worries, the next time I call the getter, I'll get back an empty game state or a game state in default order. Certainly, the user will never notice!" Mutating getters are bad design and lazy initialization is generally ill advised.Pyxis
P
0

In iOS 7, you don't normally need synthesize. If you want a custom getter, just define one. You'll get the default setter for free.

Ploughman answered 11/12, 2013 at 15:12 Comment(3)
Synthesizing has nothing to do with iOS7.Jenine
@LeoNatan: As far as I remember, you did have to @synthesize in ios5, right?Ploughman
It is the xcode and LLVM version that it is to do with - With Xcode 4.4 and LLVM Compiler 4.0 the @synthesize directive is no longer required as it will be provided by defaultFrictional

© 2022 - 2024 — McMap. All rights reserved.