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.
Related
i have 7 custom objects with the same properties, createDate and modifiedDate. can i create a method that accepts Object1 but actually takes all 7 objects?
right now, this works:
[self setCreateAndModifiedTimeWithEvent:((Object1 *) object2
WithCreateDate:[[eventsArray objectAtIndex:i] objectForKey:#"create_date"]
AndModifiedDate:[[eventsArray objectAtIndex:i] objectForKey:#"modified_date"]];
.h file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
.m file
-(void) setCreateAndModifiedTimeWithEvent:(Object1 *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp
{
object.A = #"Hello,";
object.B = #"World";
}
this would cut back on good chuck of lines of code.
i know you can do this sort of thing with UIView and its subclasses. say i have a
UITextField myTextField.
i can do
((UIScrollView *)myTextField).tag = 2;
is there anything inherently bad about typecasting my objects like this or is it acceptable?
Like Joe said, you'd be better off with something like this:
#interface DatedObject : NSObject
#property NSDate *createDate;
#property NSDate *modifiedDate;
#end
#implementation DatedObject
#synthesize createDate;
#synthesize modifiedDate;
#end
Then have each of the 7 classes inherit from the DatedObject base class. Inheritance is a fundamental part of Object Oriented Programming, and you should learn to use it (wisely).
Then your method can be:
-(void) setCreateAndModifiedTimeWithEvent:(DatedObject *)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
You could also do this with a protocol, but the nice thing about using a base class that the other classes inherit from is that you only have to implement this functionality in one place. If the 7 classes don't all currently inherit from the same base class (which would end up being the superclass of DatedObject), a protocol is probably the way to go. In that case, you can declare your method like this:
-(void) setCreateAndModifiedTimeWithEvent:(id<DatedObjectProtocol>)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
One of the big advantages to these two approaches over what you've posted in your question is that you get more help from the compiler in catching places where your code sends a message to an object that doesn't respond to it.
Andrew's answer is correct.
But, if for some reason you don't want to create a common base class or a protocol, you could always set the type of the method parameter to id, like this:
-(void) setCreateAndModifiedTimeWithEvent:(id)object
WithCreateDate:(NSString *)createStamp
AndModifiedDate:(NSString *)modifiedStamp;
Parameters of type id don't do any type checking at compile time (like the values in an NSArray) so you can call any method you want on them without generating compiler warnings (this is obviously quite dangerous if you aren't careful).
You can't use dot notation on id variable without casting, but it's better to cast from an id to a concrete type than to cast from a different unrelated type.
It doesn't actually make any difference except to your code readability though.
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;
I've been reading up on the automatically synthesized ivars. My question is, "WHere are automatically they allocated?" I would have expected them to be part of self, so that I could see them in the debugger, but it seems that the only way I can see them is by invoking the accessor method (via the gdb 'po' command). Isn't there space in the class/object's struct (as there would be for an explicitly declared ivar)?
(Is there a description of the in-memory representation for a modern Objective-C object?)
Being a C guy, it makes me very uncomfortable to not to be able to see where everything is. :-P
Looks like this will tell you:
How do automatic #synthesized ivars affect the *real* sizeof(MyClass)?
I am a C guy at heart too. Why bother using these auto generated ones? I like looking at a class and seeing what it holds onto in terms of data.
Interesting: Neat how they took the 64 bit change to make things better.
http://www.sealiesoftware.com/blog/archive/2009/01/27/objc_explain_Non-fragile_ivars.html
They are added to the objective-c object (which is a C structure) no different to a regular ivar, so for example:
#interface TestObject : NSObject {
}
#property (nonatomic, assign) int theInt;
#end
#implementation QuartzTestView
#synthesize theInt;
#end
You can refer to theInt ivar directly (not through property accessors) either:
- (void)someMethod {
theInt = 5;
}
OR
- (void)someOtherMethod {
self->theInt = 10;
}
See http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html - using the modern runtime an instance variable "will be synthesized for you". It can be nice to add a variable yourself instead though (so that you can see it when debugging in self), however you have to be careful not to do direct assignments to the instance variable for retain or copy based properties.
A class can be extended in Objective C using a category such as:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
In this small example, I would be adding the method myFabulousAddition to NSString. I could then call it by [anNSString myFabulousAddition] just as if it were part of the NSString set of methods. Great and useful.
In the Apple documents regarding Categories, the docs state:
There’s no limit to the number of
categories that you can add to a
class, but each category name must be
different, and each should declare and
define a different set of methods.
What if you have something like this:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
#interface NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition; // a DIFFERENT fabulous additional method
// BUT with same name as the other category
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
#implementation NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition {
// do something equally fabulous, but DIFFERENT...
}
#end
The lack of a name in the parenthesis indicates that the form is an extension to the class, like so:
#interface MyObject () // No name -- an extension vs category to MyObject
- (void)setNumber:(NSNumber *)newNumber;
#end
Does the category name have any meaning to the compiler or linker? Is the category name part of the method signature in anyway or is it part of a primitive namespace? If the category name is meaningless, how do you know if you are about to stomp on another method and get undefined behavior?
The way to avoid stomping on methods is to prefix your category method names, like this:
#interface NSString (MyCompanyCategoryName)
- (NSString *)MYCO_fabulousAddition;
#end
If you get a collision of method names from different categories, then which one 'wins' at run time is completely undefined.
The name of a category is almost entirely useless, with the exception being that the nameless category (i.e. ()) is reserved for class extensions. Methods from class extensions are supposed to be implemented in the class' main #implementation.
The category name doesn't mean anything special, it's just an identifier. Unless the linker (or runtime loader) decides to give you a warning, there is no way to tell that multiple categories are defining the same method.
The behavior is (largely) unpredictable - one of the categories will win out, but you can't tell which one. Also, I think it's well possible you will start out with one implementation and end up with another one (if the second category is loaded after the first).
It certainly acts as an identifier, from the programmer's point of view. In the compiler point of view category methods are simply added as an extension of the class ( from which it is extending), regardless of the name.
And yes you can add categories of the same class with the same identifiers, even with same functions. But you definitely can't override any function because categories are just part of the class once you define them ( Just like you can't override a function of a class from within that class ).
As they are being added at runtime, they don't raise any error and only at runtime compiler selects the function, which is totally unpredictable.
i believe that they don't have any meaning. You don't really use them in your code ... Since they are categories and ... the semantic of a category ... is just to categorize something, i think this is somewhat logical ...
I would say they just simply gather the methods ...
On the other hand your question is very valid ... You DON'T KNOW if you override a method. If you are in the same project then the compiler issues a warning (or an error ? i don't remember), however if you are overriding a method from a library, then .. you are out of luck ...
While I was playing and figure out how things work in https://github.com/enormego/EGOTableViewPullRefresh I found mysterious of #property and #synthesize. Here is the code I mentioned
EGORefreshTableHeaderView.h
#interface EGORefreshTableHeaderView : UIView {
id _delegate;
EGOPullRefreshState _state;
UILabel *_lastUpdatedLabel;
UILabel *_statusLabel;
CALayer *_arrowImage;
UIActivityIndicatorView *_activityView;
}
#property(nonatomic,assign) id <EGORefreshTableHeaderDelegate> delegate;
EGORefreshTableHeaderView.m
#synthesize delegate=_delegate;
I have read this http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html and from what I understand is it create new name for _delegate which is delegate. (Am I right with this understanding ?)
But I still doesn't understand why they have to make thing complicated with those #synthesize = directive.
How complicated is it, really? It's just a bit of syntax that lets you specify the ivar that you want to use to back the property for which you're telling the compiler to create accessors. If they didn't provide this or something equivalent, then you'd always have to have your property names match your ivar names, and there are reasons that you might not want that.
If you don't need to name your ivars differently, then you don't have to bother with specifying the ivar name. In fact, you don't have to create ivars at all for your properties... if you don't, the compiler will create them for you.
Update: As of the middle of 2013, LLVM defaults to synthesizing accessors for properties, so in most cases you no longer need to specify #synthesize at all. The one case where you would still use it is when you want to back the property with a different instance variable than the one that the compiler would generate for you. Also, the default name for the ivar that backs a property will be the property name prefixed with an underscore. So, the code in the OP's example could be simplified by deleting the lines:
id _delegate;
and:
#synthesize delegate=_delegate;
I've removed my previous advice against using an underscore prefix since it clearly disagreed with the current fashion and default behavior of the compiler. As far as I know, it's still poor form to use an underscore prefix for your method names, however.
Also, it has come to my attention that at least one person interpreted the first line of my response, "How complicated is it, really?" as condescending. I hope that was only one person's impression -- I definitely didn't intend any condescension, but was only trying to frame my response around the OP's assertion that the #synthesize xxx=_xxx; directive makes things complicated. There's a lot to absorb when you're starting out; hopefully the new "synthesize by default" behavior will reduce the burden for newcomers.
You are right, using
#synthesize foobar=_foobar;
is a bit pointless in most cases , but at an abstract level it does allow you to return the value of some other variable entirely. As in ...
#synthesize foobar=fluffybunny;
Lets you get or set the value of fluffybunny each time you use the accessor .foobar
However in terms of the#synthesize complexity , would you rather write
-(void)setFoobar:(id)aobject {
[self willSetValueForKey:"foobar"];
id old = foobar;
foobar = [aobject retain];
[old release];
[self didSetValueForKey:"foobar"];
}
-(id)foobar {
[self willAccessValueForKey:"foobar"];
id obj = [self primitiveValueForKey:#"foobar"];
[self didAccessValueForKey:"foobar"];
return obj;
}
Or
#synthesize foobar;
Thats not particularly well written as ive forgotten how to do them well but the #synthesize directive stops you having to write accessors so many times. It one one of the things that sucked heavily about Obj-C 1.0.
Free code , dont knock it.