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).
Related
From all code I've seen, almost always is used something like this for property scope definition:
Class extension
/*We declare the class extension*/
#interface MyClass ()
#property (nonatomic, retain) Type *aPrivateProperty;
- (void)aPrivateMethod;
#end
/*
We can use the main implementation block to implement our properties
and methods declared in the class extension.
*/
#implementation MyClass
/*Therefore we can use synthesize ;-)*/
#synthesize aPrivateProperty;
- (void)aPrivateMethod {
//Some code there
}
#end
But this is (from what I've seen) rarely used:
#interface MyClass : NSObject {
iVar *aProtectedIVar;
#public
iVar *aPublicIVar;
iVar *aSecondPublicIVar;
#protected
iVar *aSecondProtectedIVar;
#private
iVar *aPrivateIVAr;
}
#end
Why modifiers like #private, #protected and #public are not used so much in Objective-C if they are available?
Access modifiers for instance variables are rarely used because they expose more information about the structure of your object than you may wish to allow others to see. An exposure of a public variable is binding on all future implementations to have the same variable. Property, on the other hand, hides the variable, letting you change your mind later on, and compute result instead of storing it.
Property access is highly optimized in Objective-C, so there is virtually no run-time hit for exposing a property instead of a variable. Since you gain flexibility for free by switching to property, exposing variables with #public is rarely used.
I was interested why class extension, (like from example above) is used more often than #private modifier
Because class extension lets you place private properties with your .m file, rather than your .h header file. Headers included from other .m files create compile-time dependencies, which are easily avoided by placing implementation details into class extensions.
You can declare a global variable in three places.
If you declare this in .h is public:
#property (nonatomic, strong) NSString *publicString;
Instead if you declare the same in .m is private there are no need for the second way.
What is difference of these three cases (all of them are used like private fields):
1.
#interface APLParseOperation : NSOperation
#property (copy, readonly) NSData *earthquakeData;
#end
2.
#interface APLParseOperation () <NSXMLParserDelegate>
#property (nonatomic) APLEarthquake *currentEarthquakeObject;
#property (nonatomic) NSMutableArray *currentParseBatch;
#property (nonatomic) NSMutableString *currentParsedCharacterData;
#end
3.
#implementation APLParseOperation
{
NSDateFormatter *_dateFormatter;
BOOL _accumulatingParsedCharacterData;
BOOL _didAbortParsing;
NSUInteger _parsedEarthquakesCounter;
}
It's a good practice or smthing else?
I'm going to go through each example you gave, and describe them. I was just having trouble with this yesterday so I feel your pain.
1.
#interface APLParseOperation : NSOperation
#property (copy, readonly) NSData *earthquakeData;
#end
By using the #property keyword, the compiler automatically synthesizes your accessor methods for you, and also a backing instance variable. However, because you are using the readonly property attribute, the compiler is only synthesizing a getter method for you.
2.
#interface APLParseOperation () <NSXMLParserDelegate>
#property (nonatomic) APLEarthquake *currentEarthquakeObject;
#property (nonatomic) NSMutableArray *currentParseBatch;
#property (nonatomic) NSMutableString *currentParsedCharacterData;
#end
This second example is very similar to the first. However, because none of them have the readonly property attribute, they will all have getters and setter methods synthesized for them, as well as the backing instance variable.
3.
#implementation APLParseOperation
{
NSDateFormatter *_dateFormatter;
BOOL _accumulatingParsedCharacterData;
BOOL _didAbortParsing;
NSUInteger _parsedEarthquakesCounter;
}
For this last example, you are just declaring instance variables. These are also private to your implementation file, where as the other 2 examples had declarations being made in your classes interface file.
No setter or getter methods are being synthesized for you by the compiler. You are simply declaring some instance variables.
In terms of private and public, your first and second examples both provide declarations that will be visible to other classes, as long as they import the current class's header file. The first example however, only provides a way to "get" the property and read it, there is no setter method because you used the readonly property attribute. With the second example, outside classes will be able to access your getter and setter methods for your property, so they can read and write.
For the third example, these are just instance variables and they are private to your class's implementation file. Basically, no outside classes will even know that they exist.
This is not private. It is still readable by outside classes, though it can't be written.
Private properties. It can be useful if you want to write custom getters and setters. If you are not using ARC, it can be helpful for memory management.
Private members. This is my favorite. It's easy to read and easy to write.
defines a public property visible to all users of the APLParseOperation class.
defines properties through an extension, making them available only to the implementation methods.
defines instance variables which are implicitly private.
Number 1 is used when you want to make your properties public. Numbers 2 and 3 are for private properties and instance variables. You can also declare instance variables in class extensions, like this:
#interface APLParseOperation () <NSXMLParserDelegate>
{
NSDateFormatter *_dateFormatter;
BOOL _accumulatingParsedCharacterData;
BOOL _didAbortParsing;
NSUInteger _parsedEarthquakesCounter;
}
#end
There is not much difference between that and the number 3. It is a good idea to pick one style, and stick to it in all your code.
Case 1. is not private. It's a public read-only property: Reading is public, writing is only possible only in the private scope via the underlying ivar (thanks for pointing it out #mah).
Case 2. (if in a .m file) is extending the class by adding 3 private properties and making the protocol conformance private too.
Case 3. is declaring 4 private instance variables that can be used in all the implementation scope.
Objective-C best practice for private properties is case 2., as case 1. is not private at all, just read-only, and case 3. uses instance variables (aka ivar) which is less conventional than properties. More on that here: Reason to use ivars vs properties in objective c
Hope this helps,
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.
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.
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.