I want to create a class that serves as a base (or "abstract") class to be extended by subclasses. The best way I can explain what I'm 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 it like that seems nice and clean, but I can't access the ivars from my subclasses.
After doing some research, I've concluded that a good way to provide subclasses with direct access to ivars is to use the @protected
directive and include any declarations in the header file so subclasses can see it:
#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 don't have an issue with that, and it seems to work the way I want it to (e.g. subclasses can access the ivars directly, but other classes have to use accessors). However, I read blog posts or Stack Overflow answers every day that say instance variables should just be synthesized, or "I don't even touch instance variables anymore."
The thing is, I started learning Objective-C post-ARC, so I'm not fully aware of the ways in which developers had 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 actually see instance variable declarations, but maybe I'm old school. I mean, if one should "just let the compiler synthesize the instance variables," how does one include any sort of logic or "side effects" without implementing a bunch of KVO?
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 do I make sure that a value being set isn't the same as the currently set value? I'll sometimes implement a check in my mutator method like this:
- (void)setMyLazyArray:(NSArray *)array
{
if ( [array isEqualToArray:_myLazyArray] )
return;
_myLazyArray = array.mutableCopy;
}
I've read all of Apple's documentation, but half their docs date back to 2008 (or worse in some cases), so I'm not exactly sure they're the best place to get information on the matter.
I guess the gist of my question is this: Is there a preferred "modern" way of handling instance variables, variable synthesis, inheritance, scope, etc. in Objective-C? Bonus points for answers that don't include "Bro, Swift." or "You aren't using Swift?"
Any guidance would be much appreciated. Thanks for reading!