Synthesis and protected instances of variables in "Modern" Objective-C?

I want to create a class that will serve as a base (or "abstract") class that will be extended by subclasses. The best way to explain what I am talking about is with a few examples. Here's a possible interface for my superclass:

#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"

@interface MyViewController : NSViewController

@property (nonatomic, weak) id<MyViewModeControllerDelegate> delegate;
@property (nonatomic, copy) NSArray *content;

@end

      

Writing text like this seems nice and clean, but I can't seem to access the ivars from my subclasses.

After some research, I've come to the conclusion that a good way to provide subclasses with direct access to ivars is to use a directive @protected

and include any declarations in the header file so that the subclasses can see this:

#import <Cocoa/Cocoa.h>
#import "MyViewControllerDelegate.h"

@interface MyViewController : NSViewController {
@protected
    __weak id<MyViewControllerDelegate> _delegate;
    NSMutableArray *_content;
}

@property (nonatomic, weak) id<BSDViewModeControllerDelegate> delegate;
@property (nonatomic, copy) NSArray *content;

@end

      

I personally have no problem with this, and it seems to work the way I want it to (for example, subclasses can access ivars directly, but other classes need to use accessors). However, I read blog posts or Stack Overflow responses every day that say that instance variables should just be synthesized, or "I'm not even touching instance variables."

Thing is, I started learning post-ARC Objective-C, so I'm not fully aware of how developers were supposed to do things in the past. I personally like the control I have when I implement my own getters / setters, and I like being able to see the instance variable declarations, but maybe I'm old school. I mean, if you need to "just let the compiler synthesize the instance variables", how do you include any logic or "side effects" without implementing the KVO group?

For example, if my instance variables and getters / setters are synthesized, how do I initialize stuff lazily? For example, I sometimes like to do this:

- (NSArray *)myLazyArray
{
    if ( _myLazyArray == nil ) {
        self.myLazyArray = @[];
    }
    return _myLazyArray.copy;
}

      

Or how can I make sure the setpoint is not the same as the current setpoint? Sometimes I use my mutator method validation like this:

- (void)setMyLazyArray:(NSArray *)array
{
    if ( [array isEqualToArray:_myLazyArray] )
        return;
    _myLazyArray = array.mutableCopy;
}

      

I've read all of Apple's documentation, but half of their docs date from 2008 (or worse, in some cases), so I'm not entirely sure if this is the best place to get information on this subject.

I guess the gist of my question is: is there a preferred "modern" way of handling instance variables, synthesizing variables, inheritance, scoping, etc. in Objective-C? Bonus points for answers that do not include "Bro, Swift". or "Are you not using Swift?"

Any guidance would be much appreciated. Thanks for reading!

+3


source to share


1 answer


Why do your subclasses need access to your ivars? Ivars is an implementation detail and subclasses don't have to worry about it. All sorts of side effects can exist if the parent class does the logic in setter / getters. Therefore, always refer to them through the property.

Assuming this is in your subclass and you are overriding the getter property:

- (NSArray *)myLazyArray
{
    if ( super.myLazyArray == nil ) {
        // do what you need to do to populate the array
        // assign it to yourself (or super)
        self.myLazyArray = @[];
    }

    return super.myLazyArray;
}

      



And then for the setter:

- (void)setMyLazyArray:(NSArray *)array
{
    if ( [array isEqualToArray:super.myLazyArray] )
        return;
    super.myLazyArray = array.mutableCopy;
}

      

+2


source







All Articles