1

I'd like to define a member in objective C class that can only be read outside the class (public getter). The writing (setter) however shell remain private.

I've read that It's possible to conceal object's setter using the readonly property while exposing the getter using @synthesize syntax but I'm not sure how it works exactly.

Base on this information here's what I did, and I wonder what's happening here under the hood, and if this is the proper way of doing so ?

@interface MyObject : NSObject

//This line suppose to conceal both getter and setter. 
@property (readonly) MyCppBaseObject *myCppBaseObject;

- (void)setMyCppBaseObject:(NSString *)SomeInput;

@end

// This line suppose to tell the compiler that the getter is exposed
@synthesize myCppBaseObject = _myCppBaseObject;

@implementation MyObject

-(void)setMyCppBaseObject:(NSString *)SomeInput {

   if (someCondition) {
       self.myCppBaseObject = new myCppObjectDerive1(...);
   } else {
       self.myCppBaseObject = new myCppObjectDerive2(...);
   }
}
@end

P.S. I've seen a different approach explained in the following link, but I wish to understand the above implementation.

Zohar81
  • 4,554
  • 5
  • 29
  • 82
  • In my opinion, this should not work. The `@synthesize` line only tells the compiler that the variable is backed by an ivar called `_myCppBaseObject`, which should be the default. I think the assignment should fail at compilation time. – Sulthan Dec 05 '19 at 16:46

1 Answers1

2

First, you should use the private extension described in the link you provide. That's the correct way to do this.

But to your question, what you've written here is not quite correct.

@property (readonly) MyCppBaseObject *myCppBaseObject;

This line makes a promise to implement -myCppBaseObject. That's all it does. It's just a promise. If you fail to live up to your promise, the compiler will auto-generate (synthesize) one for you using a backing ivar.

- (void)setMyCppBaseObject:(NSString *)SomeInput;

This line is not correct for your purposes. It's making a public setter. But you said you don't want the setter to be public. You could put this in a private extension, however.

@synthesize myCppBaseObject = _myCppBaseObject;

This asks the compiler to create a backing ivar _myCppBaseObject for the property myCppBaseObject. This is the default behavior, however, and so isn't required. (There was a time when it was, but that was a very long time ago.)

-(void)setMyCppBaseObject:(NSString *)SomeInput {

   if (someCondition) {
       self.myCppBaseObject = new myCppObjectDerive1(...);
   } else {
       self.myCppBaseObject = new myCppObjectDerive2(...);
   }
}

This code is completely incorrect. It is an infinite loop, since self.x =... is syntactic sugar for [self setX:...]. What you mean is:

_myCppBaseObject = ...

You're going to create a lot of headaches having the name of the custom setter be exactly the expected name of the default setter, but with a different type. Don't do this. In theory it could work most of the time, but don't. Especially when there's dot-syntax involved. Especially since one of your objects does not appear to be ARC-compatible (i.e. a C++ object), this is going to really be a trap for really confusing problems. Name your setter differently.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610