Why do properties require explicit typing during compilation? - objective-c

Compilation using property syntax requires the type of the receiver to be known at compile time. I may not understand something, but this seems like a broken or incomplete compiler implementation considering that Objective-C is a dynamic language.
The property "comment" is defined with:
#property (nonatomic, retain) NSString *comment;
and synthesized with:
#synthesize comment;
"document" is an instance of one of several classes which conform to:
#protocol DocumentComment <NSObject>
#property (nonatomic, retain) NSString *comment;
#end
and is simply declared as:
id document;
When using the following property syntax:
stringObject = document.comment;
the following error is generated by gcc:
error: request for member 'comment' in something not a structure or union
However, the following equivalent receiver-method syntax, compiles without warning or error and works fine, as expected, at run-time:
stringObject = [document comment];
I don't understand why properties require the type of the receiver to be known at compile time. Is there something I am missing? I simply use the latter syntax to avoid the error in situations where the receiving object has a dynamic type. Properties seem half-baked.

Compiling property access requires knowing how to translate the property name into the correct getter/setter name. Without knowing the type of the receiver, the compiler cannot possibly know what the getter/setter is called, as the property may have overridden the name as part of its declaration, like so:
#property (nonatomic, retain, getter=myComment) NSString *comment;
If the compiler were to go ahead and generate code for your untyped example, it would generate [document comment], which will fail at runtime as the correct generated code is actually [document myComment].

Kevin nailed one of the symptoms.
When designing properties, the very specific decision was made not to support id as the target of dot syntax. Beyond the ambiguities that Kevin points out, the desire to avoid all ambiguities related to (id) receivers was considered desirable.
In general, the use of fully unqualified id is both undesirable and actively discouraged. In creating new features in the language, not supporting id discourages the proliferation fragile coding patterns across the new feature(s).

Related

Is it OK to have a method's variable with the same name as a declared property?

I understand this is probably bad practice, but I was just curious as to whether or not this has any negative side-effects, in Objective-C (trying to learn as much as I can):
#interface MyClass ()
// Declare a string called 'foo'
#property (nonatomic, strong) NSString *foo
#end
#implementation MyClass
...
- (void)modifyFoo {
// Create a local variable with the same name as a property
NSString *foo = #"Hello!" // No compiler warnings?
self.foo = foo; // <---- Is this OK?
}
This will not throw up a warning in the compiler, and sure enough, my code works as normal. If there are zero negative side-effects, does the type of property, e.g. weak/strong/assign, etc, have an influence on whether or not this is OK?
Note: I am aware that this will not work when the property is synthesised.
This is fine and is my personally preferred approach. The reason no compiler warning is generated is that the instance variable is actually named _foo. This is done by the auto-synthesise added by the compiler (it generates #synthesize foo = _foo for you). Maintaining naming consistency aids clarity.
The main potential side effect is that you inadvertently add / fail to add self. and end up trying to message nil.
Firstly:
this will not work when the property is synthesised.
Huh? Why not?
Actually, it's "OK" in the sense that it works. Actually, there's no ambiguity when you use the self keyword and the dot notation to access your property. If, however, you had an instance variable with the same name as your local variable, then the object with a narrower scope (the local variable in this case) hides the one with a wider scope (the ivar). And that may be undesirable. As far as I know, it even results in a compiler warning. Furthermore, it's hard to get it wrong and decreases overall code readability, so don't do this if you have that identically named instance variable.
If I recall correctly, recent versions of the clang/LLVM toolchain automatically synthesize properties for you, and the name of the backing ivar for a property is preceded by a leading underscore, so this should not be a problem.

Key-Value Coding with a key of 'description'

I am using Key-Value Coding to simplify updating instances of a model class:
#interface NewsItem : NSObject
{
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSString *link;
#property (nonatomic, copy) NSString *date;
using:
SEL selectorName = NSSelectorFromString(elementName);
if ([self.newsItem respondsToSelector:selectorName])
{
NSString *sanitisedElement = [self sanitiseElement:self.currentElementData];
[self.newsItem setValue:sanitisedElement forKey:elementName];
}
This works well but the 'description' property doesn't 'smell' right to me as it has overridden the base NSObject description getter (+ (NSString *)description). If the description getter is invoked now it will return irrelevant information when the caller would be expecting a description of the class.
Is it possible to safely proceed with Key-Value Coding for this class (given that I am bound to these property names by the external data source)? Or would it be wise to change the property names and manually check keys/set values instead?
You could override description in your class. This method is usually used only for debugging
and no caller can expect a specific output of that method.
But I see more general problems in your code. It is only checked that a method with the
given name exists. This does not imply that this method corresponds to a property, and even then, it does not imply that there is a setter for that property.
For example, every NSObject responds to the selector "init", so if the external
data source sends that key as "elementName", your code would immediately crash.
Therefore, an explicit list of "known keys" is needed. But then you can as well
use a mapping (NSDictionary) from external element names to internal properties
to avoid any conflicts.
I think that you are confusing methods with properties, and you are making things more complicated that how they are.
Is enough that, given an elementName that contains directly the setter name (i.e.: setDate), you invoke the selector passing that argument the object argument:
SEL selectorName = NSSelectorFromString(elementName); // elementName something like "setDate"
if ([self.newsItem respondsToSelector:selectorName])
{
[self.newsItem performSelector: selectorName withObject: sanitisedElement];
}
As for the description method, it has overridden NSObject's description, so you have two choices: name it in another way, or leave it like it is, and invoke it on super when you need the object description, with the help of Objective-C runtime:
struct objc_super superclass= { self.newItem, [self.newItem superclass] };
NSString* desc= objc_msgSendSuper(&superclass, #selector(description));
You can always override inherited methods.
By creating a property whose getter is the same as the signature of An inherited method, you are overriding it.
Is it bad? Yes if your implementation is not useful for debugging.
As best practice for KVC and KVO purposes it is a good idea to avoid potentially clashing with common inherited methods properties and ivars.
The common approach to this is to make longer property and method names and to make them more likely to be unique. One common way is by prefixing all yours with an abbreviation common to your class or framework or code.
Using something commonly used by Apple is likely to bite you in a rare and hard to debug way.
It's especially a bad idea to do this when core data is involved.
Don't be reluctant to make things longer. Code completion will type for you. Plus, a nice side effect of class specific prefixing is pseudo not only the pseudo namespace but that your class specific properties, variables, constants and methods will bubble up first in code completion.

Method parameter wihout type?

What did I do here? Can method parameters be typeless?
In a recent project which works fine, the App is in the store already - no issues so far, I did the following in a .h file:
#property (strong, nonatomic) NSManagedObject *myPerson;
- (HKPersonPicker*) initWithPerson:person;
- (HKPersonPicker*) initWithPerson:person delegate:(id <HKPersonPickerDelegate>)delegate;
I meant to do it this way but did not:
- (HKPersonPicker*) initWithPerson:(NSManagedObject*)person;
- (HKPersonPicker*) initWithPerson:(NSManagedObject*)person delegate:(id <HKPersonPickerDelegate>)delegate;
The corresponding part of the .m file:
- (HKPersonPicker*) initWithPerson:person
{
self = [super init];
if(self){
self.myPerson = person;
}
return (self);
}
- (HKPersonPicker*) initWithPerson:person delegate:(id <HKPersonPickerDelegate>)delegate
{
self = [self initWithPerson:person];
if(self){
self.delegate = delegate;
}
return (self);
}
As you can see I did not do anything special with this person object, just assigned it to the property myPerson. As I did not call any of the object's methods or accessed its data, the compiler did not need to know anything about that object. But what is it from the compiler's point of ivew? Type id? Just something? Is there any default type?
As you see, I do not have any real problem. I am just curious. Hope this question does not break any SO rule.
With C the default type is int, but with Objective-C it's id.
Missing type declarations in methods default to id. IIRC, you can see a fair number of methods without return types in Apple's runtime library.
There is no definitive problem with what you are doing, but its not really kosher at the same time. You should still have a type declaration for the sake of clarity, and maintaining good and consistent Cocoa-like code styling.
So it should really be like:
- (GSPersonPicker*) initWithPerson:(id)person;
And you should really change the property declaration:
#property (strong, nonatomic) id *myPerson;
If that is not changed, then your code is confusing. You KNOW the type that will be coming in. So let the compiler help you with meaningful warnings/errors by using types. You should also probably be using the type 'HKPerson' or whatever you have named your entity, so the compiler doesn't think its ok for you to pass in an 'HKPlace' (they will both be of type 'id' and 'NSManagedObject', which does you no favors)
More importantly, you should not be using the dynamic type (id) unless you have a reason. The compiler is there to help you. Errors and warnings are your friend, they tell you that you messed up, not the computer. When you use 'id', the compiler just goes, Oh, anything can go in here!!! And it will not detect an error where you sent that method a type that will break everything.
Now lets say that you are going to use polymorphism. IE, Lets declare a generic protocol for multiple classes to adhere to, which defines our person:
#protocol GSPerson
-(NSUInteger)age;
#end
So now lets define a couple classes, and have them subscribe to the protocol (the GSPerson thats between carrots markdown is killing me atm lol):
#import "GSPerson.h"
#interface GSSpecialPerson <GSPerson>
// code
#end
#import "GSPerson.h"
#interface GSWeirdPerson <GSPerson>
// code
#end
Then lets redefine our method signature to adhere to the protocol:
- (GSPersonPicker*) initWithPerson:(id<GSPerson>)person;
And our property declaration:
#property (strong, nonatomic) id <GSPerson> *myPerson;
Now the compiler knows that anything i pass into that method should conform to the GSPerson protocol I defined above (ie they need a method that returns the persons age). If i try to pass anything else in, it will throw compiler warnings, WHICH IS GOOD.
Even better, it will throw warnings on your polymorphic classes if they are missing their required methods.

Does the name of an argument matter when defining a function?

Does it matter if I define a function with one argument name in the .h file, for example...
-(foo *) initWithId:(NSString *)id;
And then in my implementation give the argument a different name because it hides a class property:
-(foo *) initWithID:(NSString *)idString;
I know that the autocomplete files use .h as the 'basis' for their autocomplete fillers, and while it doesn't apply to this scenario, I prefer to use the property name in my functions to remain as consistent in my coding style as possible. It makes more sense to understand that getFoo and setFoo both apply to the same property 'foo' as in -(bar *) initWithFoo:(id) foo;.
As far as I can tell, the compiler doesn't have any issues with it, but somehow it seems like it SHOULD matter.
The LLVM analyzer in Xcode does seem to care about some things like methods starting with new and copy.
Here's a sample warning when I name a property starting with new:
"Property's synthesized getter follows Cocoa naming convention for
returning 'owned' objects"
(the #property had a #synthesize that created a getter method starting with new).
No, the compiler doesn't care. Other people who read your code might care.
the only time it really matters is if you have an instance variable name with the same name.
#synthesize something;
- (void)methodForSomething:(id)something
{
something = something;
}
this will throw an error. obviously the solution is to modify your instance variables naming.
#synthesize something = _something;
other then that, parameter names dont matter.

Semantic Issue: Property's synthesized getter follows Cocoa naming convention for returning 'owned' objects

I'm currently using the iOS 5 SDK trying to develop my app.
I'm trying to make an NSString a property, and then to synthesize it in the .m file (I have done this before with no issues). Now, I came across this: "Semantic Issue: Property's synthesized getter follows Cocoa naming convention for returning 'owned' objects."
This is my code:
.h
#interface ViewController : UIViewController {
NSString *newTitle;
}
#property (strong, nonatomic) NSString *newTitle;
.m
#synthesize newTitle;
Does anyone have a clue how I could fix this?
Thanks!!
My guess is that the compiler version you’re using follows the memory management rules for declared properties, too — more specifically, for declared properties’ accessors:
You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”.
A property named newTitle, when synthesised, yields a method called -newTitle, hence the warning/error. -newTitle is supposed to be a getter method for the newTitle property, however naming conventions state that a method whose name begins with new returns an object that’s owned by the caller, which is not the case of getter methods.
You can solve this by:
Renaming that property:
#property (strong, nonatomic) NSString *theNewTitle;
Keeping the property name and specifying a getter name that doesn’t begin with one of the special method name prefixes:
#property (strong, nonatomic, getter=theNewTitle) NSString *newTitle;
Keeping both the property name and the getter name, and telling the compiler that, even though the getter name starts with new, it belongs to the none method family as opposed to the new method family:
#ifndef __has_attribute
#define __has_attribute(x) 0 // Compatibility with non-clang compilers
#endif
#if __has_attribute(objc_method_family)
#define BV_OBJC_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
#else
#define BV_OBJC_METHOD_FAMILY_NONE
#endif
#interface ViewController : UIViewController
#property (strong, nonatomic) NSString *newTitle;
- (NSString *)newTitle BV_OBJC_METHOD_FAMILY_NONE;
#end
Note that even though this solution allows you to keep newTitle as both the property name and the getter name, having a method called -newTitle that doesn’t return an object owned by the caller can be confusing for other people reading your code.
For the record, Apple have published Transitioning to ARC Release Notes, in which they state:
You cannot give a property a name that begins with new or copy.
They’ve already been notified that their statement is not quite accurate: the culprit is the getter method name, not the property name.
Edit 17 Jan 2015: I’ve just noticed a recent commit to Clang that suggests option 3 above (using objc_method_family(none)), including a fix-it, for the general case where a property name matches one of the special method family prefixes. Xcode will likely incorporate this change eventually.
Unacceptable Object Names
newButton
copyLabel
allocTitle
Acceptable Object Names
neueButton
mCopyLabel
_allocTitle
#arc #auto-synthesized #xcode-4.6.1
** EDIT **
Apparently you can't use mutableCopy either.
The name of the member starting with new is what triggers the warning. Change the name to editedTitle and the warning will go away. I was unable to find documentation confirming this but through testing was able to determine that member variables that begin with 'new' aggravate the compiler.
ARC does not allow to use "New...." in property name. but you can use "newTitle" by changing getter name.
#property (nonatomic, strong, getter=theNewTitle) NSString *newTitle;
It doesn't look like what Bavarious was suggesting was what you wanted to do. All you want to do is declare an instance variable NewTitle and then synthesize the property. We used to have to declare the instance variable and property. No more.
Now, I believe the right way of doing this is the following:
.h
#interface ViewController : UIViewController
#property (nonatomic, strong) NSString *newTitle;
.m
#synthesize newTitle = _newTitle; // Use instance variable _newTitle for storage
The instance variable for the property newTitle is synthesized. You don't want your instance variable to be the same as your property - too easy to make mistakes.
See Example: Declaring Properties and Synthesizing Accessors
In CoreData if you use "new..." in attribute (compile normally) it will crash randomly with a "bad access" exception.
There is no crash log and the line shown with the "All Exceptions Breakpoint" will not help you at all.
Writing a setter manually with the name same as the property's removed this warning.
NS_RETURNS_NOT_RETAINED is used to solve the naming problem.
#property (nonatomic, copy) NSString *newTitle NS_RETURNS_NOT_RETAINED;
We can find its definition as follows:
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
The 'ns_returns_not_retained' attribute is the complement of 'ns_returns_retained'. Where a function or method may appear to obey the Cocoa conventions and return a retained Cocoa object, this attribute can be used to indicate that the object reference returned should not be considered as an "owning" reference being returned to the caller. The Foundation framework defines a macro NS_RETURNS_NOT_RETAINED that is functionally equivalent to the one shown below.
Besides the issue that you should/can't use "new" in front of you property names, let say one more thing: Try to avoid "new" in front of names in general. "New" is dependent on time. Currently it is new for you, but some time later you maybe want to implement something new again. So using "new" in names is always bad. Try to think this way: In the programming world, "new" is always creating something: a new instance of something.
In your case when you want to assign a different title then the current name your property titleReplacement.
One more thing: Try to name functions and methods with the verb first, like setSomething or getSomething.
But in properties try to name the object first, like heightMinimum, heightMaximum, etc. -> when you use your inspector when you are coding, you always looking for objects. Try it out. ;-)
try this:-
#property (nonatomic,retain) NSString *newTitle;