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

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.

Related

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).

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.

Subclass Properties

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.

Quick inquiry about ivars scope [duplicate]

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.

What is the visibility of #synthesized instance variables?

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.