I've been reading the tutorials and I'm right now designing the model's architecture, and since I'm new to Objective-C, I'm not sure if the standards are like Java where you have public setter/getter and private attribute. This is 1 question I'd like to ask.
If the standards are so, declaring private properties are done in the *.m file #interface, but how do I #syntetize a setter/getter and how do I call them from outside: is it like [object SetProperty:property] ?
If the standards are different, can I get an example of a model class?
Thanks in advance.
A property is essentially a promise that a class provides certain accessor methods. For example:
#property(strong, nonatomic) Foo *foo;
is a promise that the class provides -foo and -setFoo: methods. So, if you want the accessors to be public, declare the property in your class's public interface (i.e. in the header file) and be done with it.
It's true that the instance variable that backs that property (_foo, unless you specify a different name) will then be accessible, but it's very poor form to access another object's instance variables directly. Many things in Objective-C are governed by convention and that's generally enough to avoid problems. Also, a given property doesn't have to be backed by any instance variable at all: a property like fullName might be computed from other properties like firstName and lastName, so there's good reason beyond mere convention for clients to avoid accessing ivars directly.
The common approach if you want to give access to your attribute is to use the keyword #property in the .h file of your class to define a property. This will automatically define a setter and a getter and you don't need to synthesise your property as of Xcode 4.4.
Your private attribute will be accessible within your .m file and will have the name of your property with "_" as a prefix by default.
You can create a private property and create public setter/getter method of your own. From this method you can assign or retrieve the value back.
#interface Person : NSObject
-(void)setTheName:(NSString *)fullName;
-(NSString *)theName;
#end
Implementation file:
#import "Person.h"
#interface Person()
#property(atomic) NSString *fullName;
#end
#implementation Person
-(void)setTheName:(NSString *)fullName{
self.fullName = fullName;
}
-(NSString *)theName{
return self.fullName;
}
#end
In the above is private however you can check the selector still exists(but throws a warning)
if ([p respondsToSelector:#selector(setFullName:)]) {
[p performSelector:#selector(setFullName:) withObject:#"Anoop"];
}
NSLog(#">>>> %#",[p theName]);
Output will be :
>>>> Anoop
However it is seldom required to set any private property from outside. If that is the requirement we can make the property public.
Well it is true that Objective-C uses another terminology than most of the other languages like Java. If I get what you're asking, if you want a property to be directly available outside the class, the property must be declared in the .h file. However if you want to hide the implementation of your code, you can declare a property in the .m file and provide setters/getters to the outside world just returning the information you want to be visible.
The #synthesize clause is to me a simpifier. By synthesizing a property the getter/setter will be automatically implemented and you don't need to do it yourself.
Does this answer your question ?
Understand that declaring a property causes the compiler to create accessor for you . so if i require a pseudo private property personally I declare it in the implementation, if i need pseudo public property i declare it in the header. public getter / private setter can be handled as indicated below. There is no need to create your own setters and getters prefer using an attribute as it saves writing setters/getters ;
in the header (.h)
#interface Person : NSObject
#property (nonatomic, readonly) NSString *fullName;
#end
in the implementation file (.m)
#import "Person.h"
#interface Person()
#property (nonatomic, readwrite) NSString *fullName;
#end
#implementation Person
... whatever this class does
// self.fullName = #"John Doe";
#end
Related
I have a block of source code getting from Github. It looks like:
Header file
#interface VTDUpcomingDisplayData : NSObject
#property (nonatomic, readonly, copy,) NSArray* sections; // array of VTDUpcomingDisplaySection
+ (instancetype)upcomingDisplayDataWithSections:(NSArray *)sections;
#end
Implementation file
#import "VTDUpcomingDisplayData.h"
#interface VTDUpcomingDisplayData()
#property (nonatomic, copy) NSArray* sections;
#end
#implementation VTDUpcomingDisplayData
+ (instancetype)upcomingDisplayDataWithSections:(NSArray *)sections
{
VTDUpcomingDisplayData* data = [[VTDUpcomingDisplayData alloc] init];
data.sections = sections;
return data;
}
This block code has two variable name called 'sections' but builds successfully. I have two questions:
First of all, I do not understand why this is allowed to happen?
Second, how to call exact the variable I want in source code?
It's normal in Objective-C, called override property attribute or redeclaring a property. You can declare a property is readonly in interface, and make it's readwrite (There’s no need to specify the readwrite attribute explicitly, but in this case You better write it) in implement.
Here's Apple document about redeclaring a property in class extension
Class extensions are often used to extend the public interface with
additional private methods or properties for use within the
implementation of the class itself. It’s common, for example, to
define a property as readonly in the interface, but as readwrite in a
class extension declared above the implementation, in order that the
internal methods of the class can change the property value directly.
First of all, I do not understand why this is allowed to happen?
Just because it's normal behavior in Objective-C
Second, how to call exact the variable I want in source code?
It's just once property, You can access it as readwrite in internal method. But in other class it's still readonly
Both declarations refer to the same property (and underlying instance variable).
However, the properties are declared differently in the header and the implementation. In the header, which defines the interface to be used by callers of this object, the property is declared readonly. In the implementation of the class the same property is missing the readonly attribute, i.e. it is read/write.
This is to allow the implementation of the class read and write access to the property but limit users of the class to only read from the property. Everybody is accessing the same property (instance variable), the only difference is the access rights of the different callers.
I understand the difference between member variable and property in Object-C, but there is one thing make me confused. See the following code.
test.h
#interface test : NSObject
#end
test.m
#interface test()
{
NSString *memberStr;
}
#property (nonatomic, strong) NSString *properyStr;
#end
As showed, the memberStr and propertyStr can't be see by outside. I want to know what is the difference between them. Because I don't how to chose the solution when i want to use local variable.
Thanks!
properyStr will have the getters and setters generated automatically.
you can define custom setter for propertyStr as below. When you use self.propertyStr, it will create a default object for you. It will be useful for initialising objects like NSMutableArray, NSMutableDictionary etc.
- (NSString *)properyStr
{
if(_propertyStr == nil)
{
_propertyStr = #"";
}
return _propertyStr;
}
memberStr will not have these options.
I understand the difference between member variable and property in Object-C
I'm not sure that you do.
A member variable is a variable that's visible only within the scope of instance methods.
A property is some attribute of the class that can be set or get. The compiler will write appropriate getters and, optionally, setters, and will organise storage for itself, unless you override any of those things.
Both member variables and properties can be declared either in the #implementation or in the #interface.
A member variable can never be accessed directly by unrelated classes, regardless of where it was declared. If it's in the #interface then it can be accessed by subclasses.
A property can always be read and, optionally, written by any other class, regardless of where it was declared. External classes can use the key-value coding mechanism even if the #property isn't visible to them.
Questions you may therefore be likely to ask:
Q) Why would I put a member variable into the #interface?
A) It's unlikely you would. It will expose it to subclasses but usually wanting to do so is a design flaw. However, in olden times you had to put all member variables into the #interface for reasons of how the old Objective-C runtime worked. So older code and stuck-in-their-ways programmers will still sometimes follow this pattern.
Q) Why would I declare a property visible only to the #implementation?
A) It's unlikely you would. However in olden times this was the only way to create member variables that weren't visible in the #interface so was the way people did most member variables for a brief period. Similarly, you could declare something, say retain, then use the getter/setter and assume correct memory management was going on, so it acted as some syntactic sugar in the days before ARC was introduced. As with the previous answer, there are therefore some people who still do so through habit and some code that still does so on account of being older. It's not something you'd often do nowadays.
EDIT: a better summary: properties adjust your class interface. Member variables adjust its implementation. In object-oriented programming you should be thinking of the two things as entirely disjoint.
One of the main purposes of object-oriented programming is to have a bunch of discrete actors that say "I can do X" with exactly how they do it being nobody else's business.
A property says what a class can do. A member variable is for the benefit of how the class does it.
Semantically they're completely separate issues.
First of memberStr is an instance variable or ivar.
There is no need to have memberStr any more if you have a property setup for this all you need is.
#interface test()
#property (nonatomic, strong) NSString *properyStr;
#end
The reason for this is that the ivar will be automatically created for you along side the setter and getter methods.
The only difference between declaring the property in the implementation files (.m) interface over the interface file (.h) is that it will be private to this class only. There are many advantages for having this such as maybe you don't want anything outside of the class to know about it but you want the property to be in scope for this class still. One thing that they are used for in this manner is when you have a readonly property declared public but you still want the setter to be in scope for this class. So you may have something like
.h
#interface MyObject : NSObject
// Other classes can see this property as it is public however they can only see
// it's getter and not the setter
#property (nonatomic, readonly) NSString *firstName;
#end
.m
#interface MyObject()
// But we still want to use the setter for this class only.
#property (nonatomic, strong) NSString *firstName;
#end
Otherwise except for being private to that class only; having the property in the implementation file (.m) will be the exact same as having it in the interface file (.h) they will act and do the same thing.
I'm beginning to learn how use Core Data for my app, and I have a question about setter and getter with NSManagedObject.
In my old models I was using this syntax to declare attributes :
#interface MyModel : NSObject
{
MyAttributeOfClass *_myAttributeOfClass
}
- (void)setMyAttributeOfClass:(MyAttributeOfClass *)anAttributeOfClass;
- (MyAttributeOfClass *)myAttributeOfClass;
I know, I could use #synthesize for doing this stuff. But if I use #synthesize with a public attribute like :
#property (nonatomic, strong) MyAttributeOfClass *myAttributeOfClass;
A developer could bypass my setter and directly set a value for myAttributeOfClass by doing this: myAttributeOfClass = bar;. I don't want to allow this behaviour because I use a setter to perform an action. If this action is not done, my class will no longer work correctly.
So, now I am migrating my old model to Core Data model subclassed from NSManagedObject.
But when I generate classes from my data model, the attributes are declared this way:
#property (nonatomic, retain) MyAttribute *myAttribute;
So, a developer can set a value for this attribute without calling a setter: myAttribute = bar; and I would like forbid it.
Any suggestions ?
Thanks !
The attributes of Core Data managed objects are not backed-up by instance variables. An attribute can be set using the property syntax:
object.myAttribute = bar;
or with Key-Value Coding:
[object setValue:bar forKey:#"myAttribute"];
and in both cases the setter method
-(void)setMyAttribute:(MyAttribute *)value;
is called. Setter and getter method are usually created dynamically at runtime, but you
can provide your own explicit setter and/or getter method.
However, it is possible to bypass the setter by calling the "primitive" accessor methods:
[object setPrimitiveValue:bar forKey:#"myAttribute"];
This is what a custom setter method would use, but anybody can call the primitive accessor,
there is no way to inhibit that.
My approach when I want to have a private setter is to have this in the header:
#property (nonatomic, strong, readonly) NSString* myProperty;
And then in the .m file add:
#interface MyClass ()
#property (nonatomic, strong) NSString* myProperty;
#end
Externally the property is read-only, but by defining a private category in the implementation file, the property is readwrite within the implementation.
Finally I'm transitioning to ARC. Sounds too late but all my projects have retrocompatiilty to 3.0 (any news about App Store unsupporting?) so I can't use it. But now I'm working in a new project with base deployment in iOS 5 so I'm using ARC.
My question is so simple. I'm used to declare private instance variables and public properties. For example:
#interface MyClass : NSObject {
#private
Var *aVar_;
Var *anotherVar_;
}
#property (nonatomic, readonly) Var *aVar;
#end
#implementation MyClass
#synthesize aVar = aVar_;
#end
Inside the class I work with instance variables, not properties.
But now I'm trying to avoid instance variables because I think there are not neccessary and redundant if I use proeprties, and I read time ago that is better to use properties instead of instance variable, but I'm not sure. That class now seems like that
#interface MyClass : NSObject
#property (nonatomic, readwrite, strong) Var *aVar;
#end
#interface MyClass()
#property (nonatomic, readwrite, strong) Var *anotherVar;
#end
#implementation MyClass
#synthesize aVar = aVar_;
#synthesize anotherVar = anotherVar_;
#end
In this case I'm still using instance variables (underscored) to manage my data because is less verbose and ARC takes into account all memory issues, but I don't know if that is correct.
Also I have another question. The property of aVar in the first chunk of code is readonly but if I use only properties I have to make that property readwrite. If I want to make the public property readonly, do I have to declare a public readonly property in the #interface and a private readwrite in private #interface?
Thank you so much.
The answer to your questions is somewhat complex, but generally you have the swing of it.
Since ARC does all the memory management for you, its often simpler to just use an ivar (private to the class, declared in the implementation) for your internal needs. In that case all usages just use the name.
With properties, you can as of Xcode 4.4 let Xcode synthesize the setter and getter, as well as the ivar. Auto-synthesized ivars are created with a leading "_" character.
You can define a property as readonly in the implementation, leave it as readonly, and set it in your code as '_foo = ....'. [Many on this site would consider this a bad practice, my point is you can do it.]
Xcode 4.4 has a warning titled "Implicit Synthesized Properties" with a default of NO. This creates a warning if you do not provide a #synthesize statement for each property, even though it will do the synthesis anyway.
Personally, I use ivars whenever I can, and only define properties when I need to either make something public to other classes, or I have categories declared in multiple files (in which case I put the interface declaration of the class extension in its own file along with properties defined in it.)
With the new Objective-C update you don't even need to synthesize the property. All you need to do is declare #property (strong, nonatomic) Var *aVar; and the compiler will automatically add the synthesizing, backing the self.aVar property with an _aVar instance variable.
If you declare a property, your implementation should generally use that property even though ARC reduces some of the memory management errors.
In init some prefer to avoid using properties because doing so might trigger KVO on an object (self) that is only partially initialized.
Im just about to refactor my current iOS project to use ARC. And after previewing the changes to migrate my current code to ARC using the "Refactor to ARC" tool i xCode, i can see my current code conventions probably not suited for ARC. Because it adds alot of __weak / __strong etc to my ivars.
Heres how my current conventions are:
i define all instance variables as private or protected ivars. and all public variables i create a #property for.
#interface TestClass
{
#private
NSMutableArray* mArray;
NSString* mString;
BOOL mMyBoolean;
}
#property (retain, nonatomic) NSString* string; // public
#end
All objects i always back with a #property, to avoid dealing with release / retain so if i have a private variable that is a reference, i just create a category in the implementation. Struct (like mMyBoolean) i just leave define as a ivar.
#interface TestClass()
#property (retain, nonatomic) NSmutableArray* mArray;
#end
#implementation TestClass
#synthesize string = mString;
#synthesize mArray;
#end;
But because the new ARC is taking care of retain / release i properly dont need private variables to be backed by #property.
So what code conventions would be more appropriate? Ive been thinking about just defining properties in the interface like this:
#interface TestClass
{
#private
NSMutableArray* mArray;
BOOL myBoolean;
}
#property (strong, nonatomic) NSString* string;
#end
#implementation TestClass
#synthesize string;
#end
And dont use category properties for private properties. (also i removed the "m" prefix) and i dont define the backed ivar that #property should use, instead i just let xcode use its autogenerated?.
This is more of a style question, so...it's hard to answer objectively, but I will throw in my two cents. There is not anything wrong with what you are doing as far as I can see. If your goal is to see what you can do to have cleaner code, then I will share my naming conventions (though one man's junk is another man's treasure, so if you don't like it then...well tough haha, you don't have to take anything away from it).
1) iVars start with m and are never public.
2) Property synthesized to a variable name starting with underbar (_), no explicit backing variable unless I need inherited classes to be able to modify a read only variable internally, in which case I need to move it to the public interface (and I still name it with an underbar to indicate to myself that it is a property variable). Properties are meant to expose some info through an interface, but since the implementation has access to everything it doesn't make sense and I never use properties in private interfaces except for the following case:
3) Properties that lazy load, or otherwise have logic outside of simply assigning to a variable. In this case, if I only override the getter or setter (not both) I will still synthesize to (_) and override the desired method (no need for explicit variable). If I override both, I don't synthesize then obviously I need an explicit backing variable (don't forget to call the KVO methods ^^).
There is no "right" way to do this kind of stuff I imagine...the only guidelines that seems to be universal are
1) Do it in a way that you and your team can understand easily
2) Do it consistently
3) In the case of an API, do it in a way that is easily understandable from looking at only the header files.