Better way to declare properties as protected - objective-c

Following this blog post, I saw a way to solve the problem I was facing.
My problem, like his, was that I have a class that has a property which must be inherited and accessed in its subclass:
#interface A : NSObject
#property (nonatomic, readonly) NSUInteger prop;
#end
#implementation A
// Don't need to synthesize nowadays
#end
#interface B : A
// No new properties
#end
#implementation B
- (void)establishValueForProp
{
_prop = 1; // PROBLEM !!!
}
#end
The solution was this:
#interface A : NSObject {
#protected
NSUInteger _prop;
}
#property (nonatomic, readonly) NSUInteger prop;
#end
What I'm wondering is if there is another way to declare properties as protected?

The way I typically do this is to create a second header, called e.g. "ClassName_ForSubclasses.h". Inside that header file, add a class extension with the properties and methods you want subclasses to be able to call and override. Then, subclasses can import that header, while other users of the class(es) don't see it.

Another common way of doing it, is by creating a separate .h file (ASubclass.h, for example) and adding something like this:
#interface A (Protected)
#property (nonatomic, readonly) NSUInteger prop;
#end
Subclassers can then import this .h and will have access to this method. Note that since categories can't add properties, you'll have to redefine this property in A's private interface (class extension). The category will then provide public access to this property. Apple takes this exact approach with UIGestureRecognizer.h and UIGestureRecognizerSubclass.h (where UIGestureRecognizer.h exposes more methods, intended for subclassers to override).
The concept of protected (or private, for that matter) methods doesn't really exist, and this is only a way to somewhat achieve similar functionality.
Personally, I just create a category in the (only) .h file of the class that exposes an otherwise public property. This way it's separated from the main public interface, and since it's possible to get to private properties anyway, I think this approach is good enough.

Related

How can I declare a private property within a named category?

I know about the possibility of declaring private properties on a class by putting them inside an unnamed category on that class declared in the implementation (.m) file of that class. That's not what I want to do.
I'm dealing with a named category on a class that adds some functionality to that class. For this functionality, it would help me very much to have a private property to use in my category - so the usual way of achieving this (described above) doesn't seem to work for me. Or does it? Please enlighten me!
Inside your category's implementation file, declare another category and call it something like MyCategoryName_Private, and declare your private properties there. Provide implementations of the -propertyName and -setPropertyName: methods using associated objects.
For example, your implementation file might look like this:
#import "SomeClass+MyCategory.h"
#import <objc/runtime.h>
#interface SomeClass (MyCategory_Private)
#property (nonatomic, strong) id somePrivateProperty;
#end
#implementation SomeClass (MyCategory_Private)
static void *AssociationKey;
- (id)somePrivateProperty
{
return objc_getAssociatedObject(self, AssociationKey);
}
- (void)setSomePrivateProperty:(id)arg
{
objc_setAssociatedObject(self, AssociationKey, arg, OBJC_ASSOCIATION_RETAIN);
}
#end
#implementation SomeClass (MyCategory)
// implement your publicly declared category methods
#end

Workaround to accomplish protected properties in Objective-C

I've been trying to find a workaround to declare #protected properties in Objective-C so only subclasses in the hierarchy can access them (read only, not write).
I read that there is no documented way of doing this so I thought of this workaround and I wanted to ask StackOverflow's opinion about it.
Every custom class at the top of the hierarchy contains three classes, one implementation and two interfaces.
Let's name them:
ClassA.h
ClassA_protected.h
ClassA.m
Then any subclass of this ClassA would be as usual:
ClassB.h
ClassB.m
First I created the interface ClassA.h where I declare a protected int variable so any subclass of ClassA can have access to it:
#interface ClassA : NSObject{
#protected
int _myProtectedInt;
}
#end
Next step is the workaround I was talking about. However, once you read it you will see that it is quite straight forward. I declared a second interface called ClassA_protected.h which actually works as an extension of ClassA.h and allows us to tag the property as readonly:
#import "ClassA.h"
#interface ClassA ()
#property (nonatomic , readonly) int myProtectedInt;
#end
Last step of preparing the protected hierarchy is to declare its implementation in ClassA.m where we only synthesize our property:
#import "ClassA_protected.h"
#implementation ClassA
#synthesize myProtectedInt = _ myProtectedInt;
#end
This way, every class that needs to be a subclass of ClassA.h, will import ClassA_protected.h instead. So a child like, for example ClassB.h, would be as follows:
#import "ClassA_protected.h"
#interface ClassB : ClassA
#end
And an example of accessing this property from ClassB.m's implementation:
#implementation ClassB
-(void) method {
//edit protected variable
_myProtectedInt= 1;
//normal access
self.muProtectedInt;
}
#end
Sure, that works fine. Apple uses the same approach for example in the UIGestureRecognizer class. Subclasses have to import the additional UIGestureRecognizerSubclass.h file and override the methods that are declared in that file.
For simple "properties" just use ivar instead. That's as good as properties for all practical purposes.
Moreover, the default is already protected.
If you ask for opinion, this is mine: If one decides to mutate your
_myProtectedInt
he will probably succed anyway, because it's definitely possible with Objective-C runtime. Except this, your solution is quite OK.
Import the protected header in the implementation only. e.g.
ClassB.h
#import "ClassA.h"
#interface ClassB : ClassA
#end
ClassB.m
#import "ClassA_protected.h"
#implementation ClassB
#end
And in a framework the protected header should be marked project so it is not included in the public headers of the framework. Apple usually use the suffix _Internal.h for their protected methods.
For init or overriding a lazy loaded get property you would need direct access to the #proteced ivar, however for your use it would be better to redeclare the property as readwrite instead then you can take advantage of any features of the setter, atomicity for example.

Inheriting accessors in Objective-C

this is my first post; this site has been an invaluable resource.
I'm fairly new to objective-c so please bear with.
So I have a base class with a few properties which I want "private" so I made them readonly. To be clear, I don't want them mutable externally, but I DO wan't to use the 'set' accessor within this class. So...
// .h file
#interface Vehicle
#property (nonatomic, readonly) int speed;
#end
Also I repeated the property declaration within a category interface block to make the accessors writable in this class
// .m file
//Private properties and methods
#interface Vehicle()
#property (nonatomic, readwrite) int speed;
#end
#implementation
#synthesize speed = _speed;
- (void) someMethod {
[self setSpeed:10]; // Works fine
}
#end
But now if I inherit this class the derived class no longer has the set accessor method (setSpeed in my case). Do I need to synthesize again? Seems like that would defeat the purpose of inheritence. I know i can modify the instance variable directly (_speed = 10;) but would rather not. I'm sure there's something wrong with my understanding. Thanks!
// Example
#interface Ship : Vehicle
#end
#implementation
- (void) someOtherMethod {
[self setSpeed: 2]; // DOES NOT WORK, would like it to
}
#end
But now if I inherit this class the derived class no longer has the set accessor method (setSpeed in my case).
Actually, it does have the set accessor, it's just that the compiler doesn't know about it. You have a choice:
put the class extension (the #interface Vehicle() .... #end bit in a separate header file that gets imported into the .m for Vehicle and its subclasses (or use a category)
redeclare the read/write property in a class extension for the subclass. To avoid a warning, use #dynamic speed in the subclass's implementation.
Since there is no such thing as 'protected' methods, you need to create a private shared header where your anonymous category goes. Then both your original implementation and your derived classes include this header to get access to this 'private' stuff.

Make an iPhone property read-only in iOS objective-c

OK basically I have a class in an iPhone app where I want it to some read only propertys. Meaning that the owning class can read and write the property, but other objects can only read it. I try the "readonly" option when I declare the property, but then my class can't even write it. What use is that?
Let's assume you wanted to create a property called foo, an int, in your class YourClass.
Do this in your interface (.h) file:
#property(readonly) int foo;
Then in your implementation (.m) file, set up a class extension where you can re-define your property.
#interface YourClass()
#property(readwrite) int foo;
#end
This results in the property being readonly publicly, but readwrite privately.
Then, of course, you synthesize foo in your implementation that follows.
#synthesize foo;
If it's not too inconvenient, just use the ivar or "backing" variable in your class to modify the value. Like this:
In your .h file:
#interface ClassName
#property (readonly,nonatomic) NSInteger readOnlyValue;
#end
In your .m file:
#implementation ClassName
#synthesize readOnlyValue = _readOnlyValue;
_readOnlyValue = 42;
#end
While you could go the route of direct iVar access as described in other answers, a better solution is typically to use class extensions. They were designed exactly to solve this problem and, by using them, you can easily refactor your code later to expose the readwrite definition of the #property to other classes in your app without exposing it to all classes.
I wrote up a detailed explanation a while ago.
You can implement your own setter in the .m class or synteshize as:
foo = _foo; so you can call _foo (private variable) internally
On further reflection, the easiest way to achieve this is to add a normal property in a class extension, then declare just the getter in the header. E.g.
Interface:
#interface MyClass: NSObject
- (NSString *)someString;
#end
Implementation:
#interface MyClass ()
#property (nonatomic, retain) NSString *someString;
#end
#implementation MyClass
#synthesize someString;
#end
You'll be able to get and set, using dot notation or otherwise, and directly access the someString instance variable within the class, and everyone that has sight of the interface will be able to get, using dot notation or otherwise.

Should I always use accessors for instance variables in Objective-C?

If I have a class with some IBOutlets, it seems kind of silly to create accessors for these.
But then I feel like I'm breaking OO practices by not always going through the accessors for instance variables.
I also feel the same way about some instance variables that should not be public, I'd rather not expose the inner workings of some classes. I can make the actual ivars private but the #property shorthand doesn't seem to be able to specify visibility. This leads me to not create accessors and just access the ivars directly. I'm not sure if this is frowned upon though. Is it?
What's the community's thoughts on this admittedly newbie question? (Please ignore dot syntax)
I'm not sure about accessing instance variables directly, I think one shouldn't, but for some variables it just doesn't make sense to use accessors. Like for the IBOutlets you mentioned.
I can only help you out with private accessors. Starting with Objective-C 2.0 you can declare extensions.
Class extensions are like “anonymous”
categories, except that the methods
they declare must be implemented in
the main #implementation block for the
corresponding class.
Just put this extension into a separate header file and you'll have private accessors that aren't visible in the header.
Public/Private
You can declare your iVars as in the #interface file to be readonly, but then re-declare them in a category so that your class can change them. Here's a quick intro to Categories.
An example:
//MyClass.h
#interface MyClass : NSObject {
NSString *name;
}
#property (readonly) NSString *name;
#end
And in the implementation file you can redeclare this:
//MyClass.m
#interface MyClass () //declare the class extension
#property (readwrite, copy) NSString *name; //redeclare the property
#end
#implementation MyClass
#synthesize name;
#end
Now, the name property is readonly external to the class, but can be changed by the class through property syntax or setter/getter syntax.
Really private iVars
If you want to keep iVars really private and only access them directly without going through #property syntax you can declare them with the #private keyword. But then you say "Ah, but they can always get the value outside the class using KVC methods such as setValueForKey:" In which case take a look at the NSKeyValueCoding protocol class method + (BOOL)accessInstanceVariablesDirectly which stops this.
IBOutlets as properties
The recommended way is to use #property and #synthesize. For Mac OS X, you can just declare them as readonly properties. For example:
//MyClass.h
#interface MyClass : NSObject {
NSView *myView;
}
#property (readonly) IBOutlet NSView *myView;
#end
//MyClass.m
#implementation MyClass
#synthesize myView;
#end