Xcode Warning: "Property '<x>' and its super class '<y>' don't have matching 'atomic' atrribute" - objective-c

I'm getting an Xcode warning when compiling several class that subclass existing Cocoa classes. For example, the following class
#interface HMAttitude : CMAttitude
{
double pitch;
double roll;
double yaw;
}
#property (readwrite) double pitch;
#property (readwrite) double roll;
#property (readwrite) double yaw;
#end
-
#implementation HMAttitude
#synthesize pitch, roll, yaw;
- (id) init
{
return [super init];
}
#end
yields three warnings
warning: property 'yaw' and its super class 'CMAttitude' don't have matching 'atomic' attribute
warning: property 'pitch' and its super class 'CMAttitude' don't have matching 'atomic' attribute
warning: property 'roll' and its super class 'CMAttitude' don't have matching 'atomic' attribute
All of the subclasses in question are required in order to create CMMotionManager and CLLocationManager subclasses capable of acting like the superclasses, only loading their data from a csv file. The only reason that I am subclassing them is to gain access (or override) their read-only properties. Without the ability to set these properties, I have no way of returning the same objects as the real CMMotionManager and CLLocationManager classes.
Currently everything works fine aside from having to use a #pragma to ignore the warning which slightly bothers me.
Does anyone know why this warning is being generated? Given the properties aren't being set to nonatomic (atomic is the default), I have no absolutely no clue.
Is there anything that I need to explicitly do in order for these properties to be atomic?

The error message is slightly confusing—if you look at the definition of those properties in the CMAttitude documentation, you'll see that they're actually declared as non-atomic. So, you should declare your properties as non-atomic as well.

Related

Instantiating multiple objects of the same class in Interface Builder results in shared property

I am trying to use NSPopUpButtons in my OSX program. In order to use KVO for its string and its index, I wrote a custom class (DLPopUpButtonManager).
#interface DLPopUpButtonManager : NSObject
#property NSArray *contentArray;
#property NSString *selectionString;
#property NSNumber *selectionIndex;
#end
That class works fine, when used only once in the program. But…
When I use more than one instance their contentArray is shared, meaning the two contentArrays point to the same instance. Huh?? That totally confuses me.
(Encapsulation, etc.)
I have two NSPopUpButtons that each are connected to an objects of class DLPopUpButtonManager. Those two classes are instantiated in Interface Builder though two objects. And in my AppDelegate I initialize them.
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (weak) IBOutlet DLPopUpButtonManager *pUBM_1;
#property (weak) IBOutlet DLPopUpButtonManager *pUBM_2;
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self.pUBM_1 setContentArray:[NSArray arrayWithObjects:#"Female", #"Male", nil]];
[self.pUBM_2 setContentArray:[NSArray arrayWithObjects:#"Tall", #"Short", nil]];
[self showDetails:nil];
}
I find that both instances (confusingly and unwanted) use the same contentArray.
I investigated using breakpoints and saw that I have indeed two separate instances of DLPopUpButtonManager, but their contentArrays have the same pointer value.
Printing description of $20: <DLPopUpButtonManager: 0x6080000100b0>
Printing description of $23: <DLPopUpButtonManager: 0x6080000100c0>
Printing description of $25: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
Printing description of $24: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
(lldb)
I can’t find anything like that through Google or here on SO. Who can tell me, what I am doing wrong here?
I uploaded a little sample program to GitHub (https://github.com/donnerluetjen/PopUpButtonEtude).
Thanks for any input on that issue.
Try moving the underlying ivars for your your array and selection index properties into a private extension in the .m file, to ensure that they are not in fact static variables.
#interface DLPopUpButtonManager (){
NSArray *_contentArray;
NSUInteger _selectionIndex;
}
Thanks to tjboneman I could solve my problem, and I read some more about instance variables and static instance variables. Here is what I found after some serious searching:
From Apple's docs, The Objective-C Language | Defining a Class:
Class Interface
...
Note: Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. These were declared in braces after the #interface declaration and before method declarations:
#interface ClassName : ItsSuperclass
{
// Instance variable declarations.
}
// Method and property declarations.
#end
Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.
...
Class Implementation
The definition of a class is structured very much like its declaration. It begins with an #implementation directive and ends with the #end directive. In addition, the class may declare instance variables in braces after the #implementation directive:
#implementation ClassName
{
// Instance variable declarations.
}
// Method definitions.
#end
Thanks again, tjboneman for pointing me in the right direction.

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.

Defining a property in iOS class extension

I would like to add a property to UITableView in a Class Extension:
#interface UITableViewController ()
#property NSString *entityString;
#end
Then I import the extension and then I use entityString property in a subclass of UITableViewController:
#implementation CustomerTableViewController
- (void)viewDidLoad {
self.entityString = #"Customer";
...
[super viewDidLoad];
}
...
Apple documentation says:
the compiler will automatically synthesize the relevant accessor
methods (...) inside the primary class
implementation.
But when I try to execute it I get this error:
-[CustomerTableViewController setEntityString:]: unrecognized selector sent to instance 0x737b670
What am I doing wrong? maybe the property cannot be accessed by subclasses?
Try using a category with Associative References instead. It is much cleaner and will work on all instances of UIButton.
UIButton+Property.h
#import <Foundation/Foundation.h>
#interface UIButton(Property)
#property (nonatomic, retain) NSObject *property;
#end
UIButton+Property.m
#import "UIButton+Property.h"
#import <objc/runtime.h>
#implementation UIButton(Property)
static char UIB_PROPERTY_KEY;
#dynamic property;
-(void)setProperty:(NSObject *)property
{
objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSObject*)property
{
return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY);
}
#end
//Example usage
#import "UIButton+Property.h"
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.property = #"HELLO";
NSLog(#"Property %#", button1.property);
button1.property = nil;
NSLog(#"Property %#", button1.property);
A class extension is used to declare additional interface -- methods and properties -- whose implementation contract will be met within the class's primary #implementation.
Which is exactly why you can't add storage -- add ivars -- via a class extension. A class extension is an interface, no more, no less. #synthesize is what creates storage for #property declarations, but #synthesize of an #property can only appear in the #implementation of the class (whether explicitly or as a default behavior of the compiler).
Since you can't recompile the framework class, you can't add ivars to it.
#prashat's answer is one way to add storage to an existing class. However, going that route is generally undesirable; hanging state off of framework classes willy-nilly is a sign of poor design and will make your application significantly more difficult to maintain over time.
Far better to revisit your design, understand why you currently require attaching state to an object that can't directly contain it, and refactoring that requirement away.
The docs state:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
When you use #property, it is roughly equivalent to declaring accessor methods. So this means you can only do such a thing if you are also the author of the "main" #implementation block of the class, which with UITableViewController, you are not.
Your only option here is Categories, which cannot add instance variables.
The docs link, and note the very last line of that page:
The implementation of the setValue: method must appear within the main #implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:.

Why does the compiler warn when redeclaring base class's readwrite property as readonly in subclass?

The Apple doc quoted later seems to indicate this is permissible, though I'll admit never having a reason to do it in a subclass until now.
I have a base class with a public readwrite property and a subclass where I redeclare the property as readonly. The subclass also has a class extension which again redeclares the property as readwrite to achieve the common "public readonly, private readwrite" Objective-C pattern. However, I get the following compiler warning:
warning: Semantic Issue: Attribute 'readonly' of property 'foo' restricts attribute 'readwrite' of property inherited from 'Base'
I'm using Xcode 4.1 build 4B110 with LLVM 2.1 (though LLVM GCC4.2 and GCC4.2 give the same warning) on 10.7.
Here's a stripped-down example which exhibits the compiler warning:
#import <Foundation/Foundation.h>
#interface Base : NSObject
#property (nonatomic, readwrite) BOOL foo;
#end
#implementation Base
#dynamic foo;
#end
// Subclass
#interface Sub : Base
#property (nonatomic, readonly) BOOL foo;
#end
// Class extension
#interface Sub ()
#property (nonatomic, readwrite) BOOL foo;
#end
#implementation Sub
#dynamic foo; // it warns with #synthesize as well
#end
Here's a relevant passage from Apple's The Objective-C Programming Language:
Property Redeclaration
You can redeclare a property in a subclass, but (with the exception of
readonly versus readwrite) you must repeat its attributes in whole in
the subclasses. The same holds true for a property declared in a
category or protocol—while the property may be redeclared in a category
or protocol, the property’s attributes must be repeated in whole.
If you declare a property in one class as readonly, you can redeclare it
as readwrite in a class extension (see “Extensions”), in a protocol, or
in a subclass (see “Subclassing with Properties”). In the case of a class
extension redeclaration, the fact that the property was redeclared prior
to any #synthesize statement causes the setter to be synthesized. The
ability to redeclare a read-only property as read/write enables two
common implementation patterns: a mutable subclass of an immutable class
(NSString, NSArray, and NSDictionary are all examples) and a property that
has a public API that is readonly but a private readwrite implementation
internal to the class. The following example shows using a class extension
to provide a property that is declared as read-only in the public header
but is redeclared privately as read/write.
I redeclare public readonly properties readwrite in class extensions all the time, but I guess I've never had cause to do it an a subclass. However, unless I'm reading it wrong, the paragraphs above seem to indicate that it's kosher. Can anyone set me straight and/or reconcile the apparent conflict between the docs and the compiler?
Why do I want to do this? My real-world situation is more complex, of course. I can make design changes to work around this if needed, but this seemed like the least-friction alternative (the need to do this at all is being driven by other changes).
It says you can redeclare a readonly property as readwrite but you're doing the opposite. You can't/shouldn't do it because it's possible to do this:
Sub* s = [[[Sub alloc] init] autorelease];
Base* b = s;
b.foo = YES; //legal for `Base` objects, but not legal for `Sub` objects
It's a violation of the the Liskov Substitution Priciple.

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.