简体   繁体   中英

How can I enforce readonly ivars in Objective-C?

To my mind state is analogous to 'moving parts'. The more moving parts, the more opportunities for things to go wrong. I take a hostile view on state. In order of preference I want an state to be:

  1. non-existant
  2. private readonly
  3. private & public readonly
  4. private read/write & public readonly
  5. public read/write

State is stored in an ivar (whether it be explicitly declared or implicitly via @synthsize). To allow public access to the state we provide accessor methods. To express the intents above in code:

  1. don't write any code
  2. Use ivar and rely on code comment to prevent (not optimal!)
  3. same as 2 plus a public getter
  4. ivar plus a public getter
  5. 4 plus public setter

How can I better solve case 2?

Firstly,

ivars/property

ivars and properties are not interchangeable. They are not the same thing. properties can be "backed" by an instance variable, but that is where the relationship ends.

Firstly, don't have explicit instance variables. To achieve point 2 (or as close as possible) define a read only property and @synthesize it like this

@synthesize myProperty = myProperty_;

Initialise the instance variable (myProperty_) to the value you want in -init and then don't assign to it again in the .m file. If you don't trust yourself not to be able to avoid assigning it in that one .m file (the trailing underscore is there to help you with that) after -init you could #define it to cause an error if used eg

#define myProperty_ someDefinitelyNonExistingIdentifier
//this is the guts of the solution. It is basically uses pointers to cast away the const.
#define EMK_INIT_READONLY_IVAR(ivar, value) (*(typeof(value) *)(&ivar) = value)


@interface Foo : NSObject
@end



@implementation
{
    id const _bar;
    const NSInteger _baz;
}



-(id)init
{
    self = [super init];
    if (self != nil)
    {
        //we could use KVC to set object values, but it's preferable to have a mechanism 
        //which is identical for object and scalar values.
        EMK_INIT_READONLY_IVAR(_bar, @"I got a brand new combine harvester, oh-ah, oh-ah!");
        EMK_INIT_READONLY_IVAR(_baz, 0xDEADBEEF);
    }
    return self;
}

@end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM