Subclass Properties - objective-c

I'd like to do the following, in an abstract way:
// .h
#interface SomeObject : NSObject
#property (readonly) NSArray myProperty;
#end
// .m
#interface SomeObject ()
#property (readwrite) NSMutableArray myProperty;
#end
#implementation SomeObject
#end
According to the section Subclassing with Properties in the Mac Developer Library it is allowed to overwrite readonly properties with readwrite. What doesn't work is using a subclass for the property type. I used NSMutableArray as an example, but it could be any other class/subclass combination.
According to inheritance rules, it should be ok though. readonly just generates the getter which also is allowed to return a subclass object.
How do you tackle such cases when you need a subclass type for some property for internal use?
An ugly way would be the following, but I'd like to avoid that as it means that I cannot use the self. getters and setters when accessing subclass methods.
// .h
#interface SomeObject : NSObject
#property (readonly) NSArray myProperty;
#end
// .m
#implementation SomeObject {
NSMutableArray _myProperty;
}
#synthesize myProperty = _myProperty;
#end

EDIT (based on your edits): Your specific case after the edit is a somewhat special and common case (if it can be both at the same time), and requires some careful consideration.
The reason this is a special is because the subclass is a mutable form of the exposed class. The caller may expect that it will not change after receiving it. But if you hand back your internal object, then it might mutate. You have several options:
Return an immutable copy. This is often the best solution for small collections. It's certainly the simplest. But if the accessor may be called often and the collection is large, it can be prohibitively expensive.
Make your internal property immutable. If requests for the property are much more common than changes to the property, it can be more efficient to recreate the object when it mutates (using arrayByAddingObject:, subarrayWithRange: and the like).
Warn the caller that the object being returned may change.... uggh... I've done this in one case where I needed the performance, but it's quite dangerous.
I've never actually done it this way, but you could also create your own copy-on-write this way: Return the mutable version directly and mark a flag that it is now "dirty." When mutation is required internally, make a mutable copy and store it in your property (letting go of the old collection). This seems a lot of complexity, but might be useful for some situations, particularly if reads and writes tend to clump separately (lots of reads followed by lots of writes).
OLD ANSWER based on NSObject vs. NSString:
I assume your goal here is to make myProperty be of some opaque type, rather than leaking the fact that it is an NSString? Perhaps so you can change your mind later on how it's actually implemented? There are a few options. The easiest is to define it of type id. Then internally just treat it as a string. id can be anything. It is usually preferred over NSObject*.
If you want more type-safety internally, then you can create a private property with another name of type NSString and return it for myProperty like this:
SomeObject.h
#interface SomeObject : NSObject
#property (readonly) id myProperty;
#end
SomeObject.m
#interface SomeObject ()
#property (readwrite) NSString *myInternalProperty;
#end
#implementation SomeObject
- (id)myProperty {
return myInternalProperty;
}
#end
Another hiding technique you can use (if hiding is very important to you) is a subclass. For example:
SomeObject.h
#class MyOpaque;
#interface SomeObject : NSObject
#property (readonly) MyOpaque *myProperty;
#end
SomeObject.m
#interface MyOpaque : NSString
#end
#implementation MyOpaque
#end
#implementation SomeObject
#end
Since the caller does not have an #interface definition for MyOpaque, he can't send messages to it without a compiler warning.

How do you tackle such cases when you need a subclass type for some
property for internal use?
Properties are explicitly not for internal use, they are members of a public interface.
If you need an internal value define a member field and override the setter of the property to set your internal value.

Related

NSArray as API property, NSMutableArray as implementation

I have a class with the following property exposed in the .h file:
#property (readonly, nonnull) NSArray<String *> * routeContext;
As you can see this is a NSArray which is not mutable. In the implementation though I want to be able to work with this array as a mutable one (NSMutableArray) so it will be easy to add, remove objects from it.
What is the best approach to do it?
I was thinking about holder a NSMutableArray in the m file which backs the read only NSArray but it seems kinda dirty to me, is there any other suggestions?
The reason I don't want to set the property to NSMutableArray although its readonly is that readonly doesn't really make sense with NSMutableArray.
Thanks.
I would add a read-write NSMutableArray property to a class extension in the .m file. Then implement the read-only property as a method that returns a copy of the mutable property.
In the .m file:
#interface SomeClass()
#property (nonatomic, strong) NSMutableArray<NSString *> *myRouteContext;
#end
#implementation SomeClass
- (NSArray<NSString *> *)routeContext {
return [myRouteContext copy];
}
#end
In all of your implementation code you use myRouteContext. Only clients of the class use routeContext for the read-only version.
I wouldn't call this "dirty" in any way. There's still only one backing instance variable implicitly created by the myRouteContext property. No instance variables are created for the read-only routeContext property. The #property for that one is just syntactic sugar for the routeContext method you implement.
In addition to the approach suggested by HangarRash i would consider two other options:
Extending routeContext property itself in the class extension:
#interface TDWObject ()
#property (copy, nonatomic, nonnull) NSMutableArray<NSString *> *routeContext;
#end
Just introducing ivar in the class extension for the property manually (and accessing it directly in the implementation):
#interface TDWObject () {
NSMutableArray<NSString *> *_routeContext;
}
#end
Personally I would prefer the manual ivar due to the following reasons:
It doesn't introduce any redundant methods that clang would synthesise otherwise (you neither need extra getter, nor setter for a NSMutableArray *)
It's the most performant (accessing ivar directly).
I would also recommend to alter the property attributes as follows:
// The header file
#interface TDWObject : NSObject
#property (copy, readonly, nonatomic, nonnull) NSArray<NSString *> *routeContext;
#end
Here a couple of clarifications regarding the properties choice:
copy storage - technically for a readonly property storage attrbitue should not make much difference, because it predominantly denotes setter semantic (if we don't count that the value for this property can also be passed as a constructor argument). However, in our case the getter is custom and returns a copy of the internal object (instead of just reference to it). If you look through Cocoa/Cocoa Touch API, they often use copy attribute when they want to explicitly say that you deal with copies of internal data structure and any changes made to the instance obtained from the property wouldn't be tracked by the owning object. (e.g. -[NSCharacterSet invertedSet]), thus it's an important part of the interface description. Why the copy is needed at all? because otherwise the client code can easily exploit the mutability of the original data, and manage its content itself.
nonatomic atomicity - first, I don't know if there is a reason to make the property atomic, and you commonly use nonatomic properties by default (because they don't have burden of synchronisation, which slows down access/read performance). Second - clang would not be able to pair a synthesized setter with a user defined getter (if you choose to use properties approaches instead of ivar). Last, but not least - since getter is user-defined, you will have to manage the synchronisation yourself, so it doesn't come "for free".
Finally, the implementation part would look like this:
#implementation TDWObject
#pragma mark Lifecycle
- (instancetype)init {
if (self = [super init]) {
_routeContext = [NSMutableArray array];
}
return self;
}
#pragma mark Actions
- (NSArray<NSString *> *)routeContext {
return [_routeContext copy];
}
- (void)addFoo {
[_routeContext addObject:#"Foo"];
}
#end

Many readonly properties, when do I initialise them?

I have a class which has 5 properties which should not be modified by other classes (and subclasses with more of these). I want to make these properties readonly, but I would then have to write a monster -init... to supply values for all these properties.
Of course I could edit the ivars directly, but I don't want to fetch the values in the constructor, as I want to pull those values from the StackExchange API. Separating this into a factory class seems more appropriate here.
tl;dr: How to initialise readonly properties from a factory class without an abnormally long constructor?
It might be a design error. If so, please add an answer suggesting a different approach, because the point of this project is to learn about design.
If you want the factory class to have the ability to update generally readonly properties and you want to avoid exceptionally long init method with a dizzying array of parameters, the typical solution in Objective-C is inelegant, but consists of defining a .h class category (used only by the factory class) that exposes the otherwise private or readonly properties.
For example, consider your CustomObject defined like so:
// CustomObject.h
#import <Foundation/Foundation.h>
#interface CustomObject : NSObject
#property (nonatomic, readonly) NSUInteger identifier; // public interface is readonly
#end
The implementation would define a private class extension that makes it clear that it's really readwrite even thought the public interface is readonly:
// CustomObject.m
#import "CustomObject.h"
#interface CustomObject ()
#property (nonatomic, readwrite) NSUInteger identifier; // it's really readwrite and setter will be synthesized, too
#end
#implementation CustomObject
#end
You can then define category header, that will be used only by the factory class, that exposes the fact that the CustomObject property of identifier is readwrite:
// CustomObject+Factory.h
#import "CustomObject.h"
#interface CustomObject (Factory)
#property (nonatomic, readwrite) NSUInteger identifier;
#end
If you look at <UIKit/UIGestureRecognizerSubclass.h> you'll see a slightly different application of the same concept, in which they expose the notion that the state property is readwrite (whereas it otherwise appears to be readonly).
Normally, in that case, you would make them publicly readonly, but privately readwrite. You can do so by adding a class extension (nameless category at the top of your .m), where you redefine the property without the readonly classifier.
// MyClass.h
#interface MyClass
#property (nonatomic, readonly) NSInteger myProperty;
#end
// MyClass.m
#interface MyClass () // Note the ()
#property (nonatomic) NSInteger myProperty;
#end
Now, within your class you can write the property, but outsiders can only read it.
You can't have it both ways. To my knowledge, Objective-C does not have the concept of "friend" members, meaning members that are accessible to only certain classes. Therefore, your only choice is to create public read-only properties and set their values in the constructor. In essence, your class could be treated as immutable. Yes, the init method may get quite long, but blame that on Objective-C's verbosity for such things. It's still the correct design choice.
MyClass.h:
#interface MyClass : NSObject
#property (copy, readonly, nonatomic) NSString *value1;
#property (assign, readonly, nonatomic) NSInteger value2;
- (instancetype)initWithValue1:(NSString *)value1 value2:(NSInteger)value2;
#end
MyClass.m:
#implementation MyClass
- (instancetype)initWithValue1:(NSString *)value1 value2:(NSInteger)value2
{
self = [super init];
if (self)
{
_value1 = value1;
_value2 = value2;
}
return self;
}
#end
You may also want to consider using JetBrains' AppCode product, as it has refactoring tools that might help with creating init methods from properties (although I haven't done this myself).
You can make constructor with only one parameter (NSArray or NSDictionary, dictionary seems less preferred because of keys), and send all 5 properties values in defined order or with defined key (as you will initialize you objects only in factory you will need to carry about correct order only in one place). In this case, if number of properties grows will be no needs to rename constructor method and adding more and more parameter names.
Also, you can simply use setVale:forKey: method, whith no matter is property readonly.
There are two approaches, and you may be trying to force these two into one model (physical object):
1) If the base provides the storage (e.g. ivars), then the values belong in the initializer. Simple as that - do guarantee the values are readonly for your sanity.
2) Lazy initialization. Your post suggests this is ideal for execution. The answer to this is that storage is an implementation detail. Let your ivars be stored by the class, and written when loaded.
Really, you want to reuse your programs and avoid making monstrous hierarchies and relying on inheritance for reuse. Consider how your 5 properties may be abstracted -- this would be by one or multiple helper classes (e.g. which provide these properties) which adopt a common protocol of the properties they vend. In this way, you may load lazily, copy, use initialization, or a number of other approaches.
Then your "subclasses" would just have a property which contains one of these objects which represents the "Base 5 Properties". Subclasses would not need 5 parameters. They would only need an id<MonBase5Properties> parameter. Again, an implementation (which adopts the protocol) may store the properties, and another may load them on demand. Either way, it's a convenient way to pack up a common set of data or interface into a type (class or protocol).

#property vs just declaring getter and setter

Is there any difference in behaviour - either at compile time or at run time - between this code...
// MyClass.h
#interface MyClass : NSObject
#property (nonatomic) SomeType myProperty;
#end
// MyClass.m
#implementation MyClass
#end
... and this code?
// MyClass.h
#interface MyClass : NSObject
-(SomeType)myProperty;
-(void)setMyProperty:(SomeType)myProperty;
#end
// MyClass.m
#implementation MyClass {
SomeType _myProperty;
}
-(SomeType)myProperty {
return _myProperty;
}
-(void)setMyProperty:(SomeType)myProperty {
_myProperty = myProperty;
}
#end
Obviously, the former version is more succinct and readable, but is there any difference in behavior? Do the synthesized getter and setter do anything more sophisticated than my straightforward implementation here? Is the declaration of a property distinguishable by introspection functions from declaration of a getter and setter? Are there any other differences I haven't thought of?
Short answer: No difference. However, some property attributes (copy or atomic) may require different accessor methods.
Long answer: There is a group of introspection functions that allow you to access all #properties declared for given class or protocol:
class_getProperty
class_copyPropertyList
protocol_getProperty
protocol_copyPropertyList
property_getName
property_getAttributes
I don't think any of these functions is useful in production code, because this is basically an implementation detail of the class. Also, there may be a getter/setter exposed in the public interface and a private property hidden in class extension.
Oh, and there's one other difference: Xcode highlights properties and plain getters differently :)
One difference is memory management. You can configure your properties to for example copy the object being set or to use a weak variable. Your code seem to be assuming ARC is active, since you are not releasing the old object and retaining the new object.
Before ARC a typical setter would to something like
-(void)setMyProperty:(SomeType *)myProperty {
if (myProperty == _myProperty) return;
[_myProperty release];
_myProperty = myProperty;
[_myProperty retain];
}
When you say you use ARC, then there is only a small difference. But none that matters.
Your ivar is #protected.
A #property creates an ivar which is #private.
Generally speaking:
So when you subclass, it is possible for your subclass to directly access the ivar you created, but not the one the property created.
BUT since you put your ivar in the #implementation block, the ivar is never seen by the subclass.
Without ARC however and SomeType being not an Objective-C object, there is a big difference. Then your setter/getter wouldn't have retain/release messages included.

Objective-C: Compiler error when overriding a superclass getter and trying to access ivar

I'm working on building an iOS 6 app.
I have a class TDBeam which inherits from superclass TDWeapon.
The superclass TDWeapon declares a #property in the TDWeapon.h file:
#interface TDWeapon : UIView
#property (nonatomic) int damage;
#end
I do not explicitly #synthesize the property, as I'm letting Xcode automatically do so.
In the subclass TDBeam I override the getter in the TDBeam.m file:
#import "TDBeam.h"
#implementation TDBeam
- (int)damage {
return _damage;
}
#end
Xcode auto-completes the getter method name, as expected. But when I attempt to reference the _damage instance variable (inherited from the superclass), I get a compiler error:
Use of undeclared identifier '_damage'
What am I doing wrong here? I've tried explicitly adding #synthesize, and changing the name of the _damage ivar, but the compiler doesn't "see" it or any other ivars from the superclass. I thought ivars were visible and accessible from subclasses?
Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of #synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.
If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.
There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.
What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use #property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.
At least that's where i've landed on the issue, although I'd a total newb to subclassing.
The idea of creating private headers to host your anonymous category and re-#sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.
Edit
Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.
MYFoo.h
#import <Foundation/Foundation.h>
#interface MYFoo : NSObject
// Optional, depending on your class
#property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
#end
MYFoo.m
#import "MYFoo.h"
#interface MYFoo ()
#property (strong, nonatomic, readwrite) NSString * myProperty;
#end
#implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
#end
Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.
If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).
Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.

Objective-C: "warning: property 'owner' type does not match protocol 'PieceModel' property type"

I'm getting this warning. What I'm trying to do is have a family of classes and a parallel family of protocols. The class Piece has a declaration like this:
#interface Piece : NSManagedObject <PieceModel>
{
}
...
#property (nonatomic, retain) Player *owner;
...
#end
PieceModel has this
#protocol PieceModel <NSObject>
...
#property (readonly, nonatomic, retain) id <PlayerModel> owner;
#end
And of course:
#interface Player : NSManagedObject <PlayerModel> { ...
It seems to me this should all be totally safe. Users of the protocols see that something conforming to the PieceModel protocol has an owner that should conform to the PlayerModel protocol. And in fact, every instance of the Piece class returns a Player instance for the owner property, which conforms to the PlayerModel protocol. I do see why there is such a warning. It would not be so safe to try to assign any object that conforms to PlayerModel to owner, since it might not belong to the Player class, but that is not a problem in this case because the property is declared as readonly for the protocol.
Notice I also declared the property as retain, which if I am not mistaken is meaningless for a readonly property, but I also got a different warning about a mismatch between the protocol and the class if I didn't do that. At least the compiler does not complain that one property is readonly and the other is not.
I know I could just declare the class property as returning id <PlayerModel>, but that would be undesirable for a couple reasons. Users of Piece objects that have them statically typed as Pieces would have to do a cast to get something statically typed as a Player. Also, I would have to write the property implementation myself instead of just using #synthesize, or in this case actually #dynamic; Core Data generates the property implementations.
So, can I instruct the compiler to suppress this warning? Or is there a better way to write this code that won't generate the warning?
This generates no warnings ...
#protocol PlayerModel <NSObject>
#end
#protocol PieceModel <NSObject>
- (id<PlayerModel>)owner;
#end
#interface Player : NSObject <PlayerModel> {
}
#end
#interface Piece : NSObject <PieceModel> {
}
#property (nonatomic,retain) Player* owner;
#end
You will then of course not be able to use #synthesize for PieceModel.owner, but that's not so much extra work. Remember that #property declarations are basically just short hand for declaring the setter and getter and defining the behavior of methods generated by #synthesize.
Also keep in mind that dot notation for accessing properties is just syntactic sugar, so if you're fond of dot notation, you'll still be able to use it for accessing 'owner' on variables declared as id<PieceModel>.
Is owner a relationship in your data model? If so, you might find the compiler is confused because NSManagedObject needs to respond to it.
Otherwise, it looks like a limitation of the way properties are handled in subclasses or implementations of protocols. If you replace NSManagedObject by NSObject in Piece and Player and you still get the issue, it might be worth reporting a bug to Apple.
As a work around for the issue, I think you should not declare the property in Piece and declare a separate setter for owner i.e.
#interface Piece : NSManagedObject <PieceModel>
{
}
...
//#property (readonly, nonatomic, retain) id<PlayerModel> owner;
// property declaration not needed because it's in the protocol
-(void) setOwner: (Player*) newOwner;
...
#end
and implement the setter manually.
On an unrelated note, I wouldn't bother declaring properties as nonatomic ever unless I had evidence from a profiler that it provides a significant performance boost.