I had some discussion related to the use of properties and instance variables at work, therefore I would like to find a wiki answer for that. Now, I know there's no real private member type in objective-c, everything is pretty much public. However, I'm a little bit concerned about the way we should design our classes and also to comply to OOP principles. I would like to hear opinions of these three design approaches:
A. According to various post and even to a new Stanford university iPhone development courses, you should always use properties everywhere you can. However IMHO, this approach brakes OOP design principles because in this case, all members become public. Why do I need to publish all my internal/local instance variables to outside? Also, there's some very little (but still) overhead if you use synthesized setters via properties, instead using local ivar directly. Here's a sample:
//==== header file =====//
#interface MyClass : NSObject
#property (nonatomic, retain) NSString *publicMemberWithProperty;
#property (nonatomic, retain) NSString *propertyForPrivateMember;
#end
B. Another approach is to declare ivars in header file (without declaring relative properties) for private members, and in the same header file, to declare pure properties (without declaring relative ivars) for public members. In such case, ivars would be used directly in the class. This approach makes sense but not uses all benefits from properties because we have manually to release old values before setting the new ones. Here's a sample:
//==== header file =====//
#interface MyClass : NSObject{
NSString *_privateMember;
}
#property (nonatomic, retain) NSString *publicMemberWithProperty;
#end
C. To declare pure properties (without declaring relative ivars) for public members in header file, and to declare pure properties (without declaring relative ivars) for private members in private interface in implementation file. This approach IMHO is more clear than the first one, but the same question remains: why do we have to have properties for internal/local members? Here's a sample:
//==== header file =====//
#interface MyClass : NSObject
#property (nonatomic, retain) NSString *publicMemberWithProperty;
#end
//==== implementation file =====//
#interface MyClass()
#property (nonatomic, retain) NSString *propertyForPrivateMember;
#end
This decision freedom annoys me a little bit and I would like to find a confirmation from respective sources about how things should be done. However, I was unable to find such strict statements in Apple docs on that, so please post a link to apple docs if any exists, or to any other theory that clears that.
By using class extensions you can have private properties.
A class extension syntax is simple:
Inside the .m-file, that has the class, create a unnamed category:
.h
#interface OverlayViewController : UIViewController <VSClickWheelViewDelegate>
- (IBAction)moreButtonClicked:(id)sender;
- (IBAction)cancelButtonClicked:(id)sender;
#end
.m
#import "OverlayViewController.h"
#interface OverlayViewController ()
#property(nonatomic) NSInteger amount;
#property(retain,nonatomic)NSArray *colors;
#end
#implementation OverlayViewController
#synthesize amount = amount_;
#synthesize colors = colors_;
//…
#end
Now you got all the aspects of properties for private members, without exposing them to public. There should be no overhead to synthesized properties to written getter/setters, as the compiler will create more or less the same at compile time.
Note that this code uses synthesized ivars. No ivar declaration in the header is needed.
There is a nice cocoawithlove article, about this approach.
You also ask why to use properties for private ivars. There are several good reasons:
properties take care for ownership and memory management.
at any point in future you can decide, to write a custom getter/setter. i.e. to reload a tableview, once a NSArray ivar was newly set. If you used properties consequently, no other changes are needed.
Key Value Coding support properties.
public readonly properties can be re-declared to private readwrite properties.
Since LLVM 3 it is also possible, to declare ivars in class extensions
#interface OverlayViewController (){
NSInteger amount;
NSArray *colors;
}
#end
or even at the implementation block
#implementation OverlayViewController{
NSInteger amount;
NSArray *colors;
}
//…
#end
see "WWDC2011: Session 322 - Objective-C Advancements in Depth" (~03:00)
There really is not a clean, safe, zero overhead, solution to this which is directly supported by the language. Many people are content with the current visibility features, while many feel they are lacking.
The runtime could (but does not) make this distinction with ivars and methods. First class support would be best, IMO. Until then, we have some abstraction idioms:
Option A
Is bad - everything's visible. I don't agree that it is a good approach, and that is not OOD (IMO). If everything is visible, then your class should either:
support all cases for how the client may use your class (usually unreasonable or undesirable)
or you provide them with a ton of rules via documentation (doc updates are likely to go unnoticed)
or the accessors should have no side effects (not OOD, and frequently translates to 'do not override accessors')
Option B
Has the deficiencies of Option A,, and like Option A, members may be accessed by key.
Option C
This is slightly safer. Like all the others, you can still use keyed access, and subclasses may override your accessors (even if unknowingly).
Option D
One approach to this is to write your class as a wrapper over over an implementation type. You can use an ObjC type or a C++ type for this. You may favor C++ where speed is important (it was mentioned in the OP).
A simple approach to this would take one of the forms:
// inner ObjC type
#class MONObjectImp;
#interface MONObject : NSObject
{
#private
MONObjectImp * imp;
}
#end
// Inner C++ type - Variant A
class MONObjectImp { ... };
#interface MONObject : NSObject
{
#private
MONObjectImp imp;
}
#end
// Inner C++ type - Variant B
class MONObjectImp;
#interface MONObject : NSObject
{
#private
MON::t_auto_pointer<MONObjectImp> imp;
}
#end
(Note: Since this was originally written, the ability to declare ivars in the #implementation block has been introduced. You should declare your C++ types there if it isn't necessary to support older toolchains or the 'fragile' 32-bit OS X ABI).
C++ Variant A is not as 'safe' as the others, because it requires the class' declaration visible to the client. In the other cases, you can declare and define the Imp class in the implementation file -- hiding it from clients.
Then you can expose the interface you choose. Of course, clients can still access your members if they really want to via the runtime. This would be easiest for them to do safely with the ObjC Imp type -- the objc runtime does not support C++ semantics for members, so clients would be asking for UB (IOW it's all POD to the runtime).
The runtime cost for the ObjC implementation is to write a new type, to create a new Imp instance for each instance, and a good amount of doubling of messaging.
The C++ type will cost practically nothing, apart from the allocation (Variant B).
Option E
Other approaches often dissociate ivars from interfaces. While this is a good thing, it's also very unusual for ObjC types. ObjC types/designs often maintain close relations to their ivars and accessors -- so you'll face resistance from some other devs.
Similarly to C++, Objective C provides public, private, and protected scopes. It also provides a package scope which is similar to package scope as defined in Java.
Public variables of classes can be references anywhere in the program.
Private variables can only be referenced within messages of the class that declares it. It could be used within messages that belong to ANY instance of the same class.
Package scope is similar to public scope within the same image, i.e. executable or library. According to Apple’s documentation, on 64-bit architectures, variables of package scope defined within a different image are to be treated as private.
Variable scope is defined by #public, #private, #protected, #package modifiers. These modifiers can be used both in a way similar to C++ or Java. All variables listed under a scope declaration belong to the same scope. Also, variables can be listed on the same line where the scope is declared.
#interface VariableScope : NSObject {
#public
int iVar0;
#protected
int iVar1;
#private
int iVar2;
#package
int iVar3;
#public int iVar01, iVar02;
#protected int iVar11, iVar12;
#private int iVar21, iVar22;
#package int iVar31, iVar32;
}
#end
For more info use the below link
http://cocoacast.com/?q=node/100
Related
So in the guidelines it says:
For code that will run on iOS only, use of automatically synthesized instance variables is preferred.
When synthesizing the instance variable, use #synthesize var = var_; as this prevents accidentally calling var = blah; when self.var = blah; is intended.
// Header file
#interface Foo : NSObject
// A guy walks into a bar.
#property(nonatomic, copy) NSString *bar;
#end
// Implementation file
#interface Foo ()
#property(nonatomic, retain) NSArray *baz;
#end
#implementation Foo
#synthesize bar = bar_;
#synthesize baz = baz_;
#end
Question is, does this apply to public variables only or private too? It's not really clear on the documentation, but would like to have some thoughts or perspective on why "if" this is only for public or private only? I think that it just makes sense for all public/private so that you don't mess up ivars and using the property
I don't think it particularly matters whether the variables in question are public or private. The practice of synthesizing under a different name makes it explicit when you are accessing the variable directly instead of using the generated accessor method.
Perhaps there's a different question underlying what you're asking: should I typically access private ivars via the accessor or directly? I think most skilled iOS devs tend to use accessors unless there is some particular reason not to (performance, avoiding side effects like KVO, etc.). Doing so is more future-proof and allows for flexibility in the underlying implementation. In a very small way, you're coding to an interface rather than an implementation.
It also might be worth pointing out that the default behavior of Clang is going to change in the future so that property-backing ivars are synthesized named _foo by default. Clearly the powers-that-be consider consider underscoring ivars to be a best-practice.
I am pretty sure much of it comes down to personal preferences, so here are mine, for what they are worth:
I like to distinguish between public properties and "private" instance vars.
Properties are always accessed through their accessors, except for initialization (and within a manually created accessor method, for obvious reasons). Hence, the underscore in the backing ivar is useful, and not really an issue in my daily use of the properties.
Instance vars are used to hold state that is used internally in the methods, but not (directly) by other classes.
I have become very fond of declaring my instance variables in the .m file. Nice, clean and easy (no switching back and forth between .h and .m to declare ivars).
I find that this distinction helps me clear my mind and determine if a property is something outside agents should get and/or set directly (a property in .h), or if it is really just a help to get my method implementations to work (an ivar in .m).
I'd agree with Paul.s. that consistency is your friend, but to me, distinction is a friend, too.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
When do I need to have both iVar and a property?
I keep seeing the following in objective-C code.
#interface Contact : RKObject {
NSNumber* _identifier;
NSString* _name;
NSString* _company;
}
#property (nonatomic, retain) NSNumber* identifier;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, retain) NSString* company;
Why is the bit inside of the block with the interface also required? Is that instead of using #synthesize?
The block inside the #interface are the ivars for your class, while the 3 elements below it are the properties, that is accessors (getters and setters) for your ivars.
You typically access an object’s properties (in the sense of its
attributes and relationships) through a pair of accessor
(getter/setter) methods. By using accessor methods, you adhere to the
principle of encapsulation. You can exercise tight
control of the behavior of the getter/setter pair and the underlying
state management while clients of the API remain insulated from the
implementation changes.
Although using accessor methods therefore has significant advantages,
writing accessor methods is a tedious process. Moreover, aspects of
the property that may be important to consumers of the API are left
obscured—such as whether the accessor methods are thread-safe or
whether new values are copied when set.
Declared properties address these issues by providing the following
features:
The property declaration provides a clear, explicit specification of how the accessor methods behave.
The compiler can synthesize accessor methods for you, according to the specification you provide in the declaration.
Properties are represented syntactically as identifiers and are scoped, so the compiler can detect use of undeclared properties.
Reference : https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1
Extending Dr. kameleon's answer, the iVars are unnecessary in this case, as they can be declared explicitly at the #synthesize line. For instance, #synthesize name = _name would be the same as declaring the iVar in the .h (note that the property is required for this syntax). Neither one is more OK than the other, one is just more efficient coding.
I have started work at a new company and one of the guidelines I have been told to adhere to by my team lead is to rarely use retain/release and instead rely on properties for memory management. I can see the appeal of keeping the code clear and leaving less room for mistakes but opening up the interfaces like this makes me uncomfortable. Generally speaking the architecture is very good but I have always been pedantic about closing up my classes to the outside world.
Is using properties like this an accepted design methodology in objective-c? Can anyone provide me with links or a clue where my new team may have picked up this strategy?
There is no need to expose properties to the entire world. In your implementation .m file you can add a little category to declare 'private' properties. E.g.
#import "Class.h"
#interface Class ()
#property (nonatomic, strong) NSDate *privateProperty
#end
#implementation Class
#synthesize privateProperty;
...
#end
Nothing in Objective-C is ever really private in strict terms, so I'd say this was good practice — it hides almost all of the retain/release stuff without requiring an ARC-compatible runtime and has the side effect of not requiring you to mention your instance variables in the header at all (though there are other ways to achieve that).
As a historical note, I think this was the first way to move instance variables out of the header — which is something permitted only by the 'new' runtime on iOS and 64bit Intel 10.6+ — so that may be a secondary reason why your team have settled upon it. Unless they've explicitly told you to make your classes transparent, they may actually be completely in agreement with your feeling (and the well accepted object oriented principle) that implementations should be opaque.
You don't have to declare your properties publicly. Using a class category or class extension, you can place your properties within the implementation.
For example:
// in AnObject.h
#interface AnObject : NSObject
#end
// in AnObject.m
#interface AnObject () // () is class extension, (foo) is a class category
#property (retain) NSString *foo;
#end
#implementation AnObject
#synthesize foo;
#end
For more information, see Apple's documentation.
I learned something new while trying to figure out why my readwrite property declared in a private Category wasn't generating a setter. It was because my Category was named:
// .m
#interface MyClass (private)
#property (readwrite, copy) NSArray* myProperty;
#end
Changing it to:
// .m
#interface MyClass ()
#property (readwrite, copy) NSArray* myProperty;
#end
and my setter is synthesized. I now know that Class Extension is not just another name for an anonymous Category. Leaving a Category unnamed causes it to morph into a different beast: one that now gives compile-time method implementation enforcement and allows you to add ivars. I now understand the general philosophies underlying each of these: Categories are generally used to add methods to any class at runtime, and Class Extensions are generally used to enforce private API implementation and add ivars. I accept this.
But there are trifles that confuse me. First, at a hight level: Why differentiate like this? These concepts seem like similar ideas that can't decide if they are the same, or different concepts. If they are the same, I would expect the exact same things to be possible using a Category with no name as is with a named Category (which they are not). If they are different, (which they are) I would expect a greater syntactical disparity between the two. It seems odd to say, "Oh, by the way, to implement a Class Extension, just write a Category, but leave out the name. It magically changes."
Second, on the topic of compile time enforcement: If you can't add properties in a named Category, why does doing so convince the compiler that you did just that? To clarify, I'll illustrate with my example. I can declare a readonly property in the header file:
// .h
#interface MyClass : NSObject
#property (readonly, copy) NSString* myString;
#end
Now, I want to head over to the implementation file and give myself private readwrite access to the property. If I do it correctly:
// .m
#interface MyClass ()
#property (readwrite, copy) NSString* myString;
#end
I get a warning when I don't synthesize, and when I do, I can set the property and everything is peachy. But, frustratingly, if I happen to be slightly misguided about the difference between Category and Class Extension and I try:
// .m
#interface MyClass (private)
#property (readwrite, copy) NSString* myString;
#end
The compiler is completely pacified into thinking that the property is readwrite. I get no warning, and not even the nice compile error "Object cannot be set - either readonly property or no setter found" upon setting myString that I would had I not declared the readwrite property in the Category. I just get the "Does not respond to selector" exception at runtime. If adding ivars and properties is not supported by (named) Categories, is it too much to ask that the compiler play by the same rules? Am I missing some grand design philosophy?
Class extensions were added in Objective-C 2.0 to solve two specific problems:
Allow an object to have a "private" interface that is checked by the compiler.
Allow publicly-readable, privately-writable properties.
Private Interface
Before Objective-C 2.0, if a developer wanted to have a set of methods in Objective-C, they often declared a "Private" category in the class's implementation file:
#interface MyClass (Private)
- (id)awesomePrivateMethod;
#end
However, these private methods were often mixed into the class's #implementation block (not a separate #implementation block for the Private category). And why not? These aren't really extensions to the class; they just make up for the lack of public/private restrictions in Objective-C categories.
The problem is that Objective-C compilers assume that methods declared in a category will be implemented elsewhere, so they don't check to make sure the methods are implemented. Thus, a developer could declare awesomePrivateMethod but fail to implement it, and the compiler wouldn't warn them of the problem. That is the problem you noticed: in a category, you can declare a property (or a method) but fail to get a warning if you never actually implement it -- that's because the compiler expects it to be implemented "somewhere" (most likely, in another compilation unit independent of this one).
Enter class extensions. Methods declared in a class extension are assumed to be implemented in the main #implementation block; if they're not, the compiler will issue a warning.
Publicly-Readable, Privately-Writeable Properties
It is often beneficial to implement an immutable data structure -- that is, one in which outside code can't use a setter to modify the object's state. However, it can still be nice to have a writable property for internal use. Class extensions allow that: in the public interface, a developer can declare a property to be read-only, but then declare it to be writable in the class extension. To outside code, the property will be read-only, but a setter can be used internally.
So Why Can't I Declare a Writable Property in a Category?
Categories cannot add instance variables. A setter often requires some sort of backing storage. It was decided that allowing a category to declare a property that likely required a backing store was A Bad Thing™. Hence, a category cannot declare a writable property.
They Look Similar, But Are Different
The confusion lies in the idea that a class extension is just an "unnamed category". The syntax is similar and implies this idea; I imagine it was just chosen because it was familiar to Objective-C programmers and, in some ways, class extensions are like categories. They are alike in that both features allow you to add methods (and properties) to an existing class, but they serve different purposes and thus allow different behaviors.
You're confused by the syntactic similarity. A class extension is not just an unnamed category. A class extension is a way to make part of your interface private and part public — both are treated as part of the class's interface declaration. Being part of the class's interface, an extension must be defined as part of the class.
A category, on the other hand, is a way of adding methods to an existing class at runtime. This could be, for example, in a separate bundle that is only loaded on Thursdays.
For most of Objective-C's history, it was impossible to add instance variables to a class at runtime, when categories are loaded. This has been worked around very recently in the new runtime, but the language still shows the scars of its fragile base classes. One of these is that the language doesn't support categories adding instance variables. You'll have to write out the getters and setters yourself, old-school style.
Instance variables in categories are somewhat tricky, too. Since they aren't necessarily present when the instance is created and the initializer may not know anything about them, initializing them is a problem that doesn't exist with normal instance variables.
You can add a property in a category, you just can't synthesize it. If you use a category, you will not get a compile warning because it expects the setter to be implemented in the category.
Just a little clarification about the REASON for the different behavior of unnamed categories (now known as Class Extensions) and normal (named) categories.
The thing is very simple. You can have MANY categories extending the same class, loaded at runtime, without the compiler and linker ever knowing. (consider the many beautiful extensions people wrote to NSObject, that add it functionality post-hoc).
Now Objective-C has no concept of NAME SPACE. Therefore, having iVars defined in a named category could create a symbol clash in runtime. If two different categories would be able to define the same
#interface myObject (extensionA) {
NSString *myPrivateName;
}
#end
#interface myObject (extensionB) {
NSString *myPrivateName;
}
#end
then at the very least, there will be memory overrun at runtime.
In contradiction, Class extensions have NO NAME, and thus there can be only ONE. That's why you can define iVars there. They are assured to be unique.
As for the compiler errors and warnings related to categories and class extensions + ivars and property definitions, I have to agree they are not so helpful, and I spent too much time trying to understand why things compile or not, and how they work (if they work) after they compile.
I'm rather confused about properties and instance variables in Objective-C.
I'm about half-way through Aaron Hillegass's "Cocoa Programming for Mac OS X" and everything is logical. You would declare a class something like this:
#class Something;
#interface MyClass : NSObject {
NSString *name;
NSArray *items;
Something *something;
IBOutlet NSTextField *myTextField;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSArray *items;
Since other objects need to manipulate our name and items instance variables, we use #property/#synthesize to generate accessors/mutators for them. Within our class, we don't use the accessors/mutators—we just interact with the instance variable directly.
something is just an instance variable that we're going to use in our class, and since no one else needs to use it, we don't create a pair of accessors and mutators for it.
We need to interact with a text field in our UI, so we declare an IBOutlet for it, connect it, and we're done.
All very logical.
However, in the iPhone world, things seem to be different. People declare properties for every single instance variable, declare properties for IBOutlets, and use accessors/mutators to interact with instance variables within the class (e.g. they would write [self setName:#"Test"] rather than name = #"Test").
Why? What is going on? Are these differences iPhone-specific? What are the advantages of declaring properties for all instance variables, declaring properties for IBOutlets, and using accessors/mutators within your own class?
In the iPhone world, there's no garbage collector available. You'll have to carefully manage memory with reference counting. With that in mind, consider the difference between:
name = #"Test";
and
self.name = #"Test";
// which is equivalent to:
[self setName: #"Test"];
If you directly set the instance variable, without prior consideration, you'll lose the reference to the previous value and you can't adjust its retain count (you should have released it manually). If you access it through a property, it'll be handled automatically for you, along with incrementing the retain count of the newly assigned object.
The fundamental concept is not iPhone specific but it becomes crucial in an environment without the garbage collector.
Properties are used to generate accessors for instance variables, there's no magic happening.
You can implement the same accessors by hand.
You can find in Aaron Hillegass's book examples of 3 memory management strategies for member variables. They are assign/copy/retain. You select one of those as required for given variable.
I assume you understand memory management in Objective-c ...
Accessors hide the complexity and differences of memory management for each variable.
For example:
name = #"Test"
is a simple assignment, name now holds reference to NSString #"Test". However you could decide to use copy or retain. No matter which version of memory management you chose accessor hides the complexity and you always access the variable with (or similar):
[self setName:#"Test"]
[self name]
Now setName: might use assign/copy or retain and you don't have to worry about it.
My guess is that iPhone tutorials use properties to make it easier for new developers to jump through memory management (even though it's handy to generate appropriate accessors with properties rather than implement them by hand every time).
However, in the iPhone world, things seem to be different. People declare properties for every single instance variable, declare properties for IBOutlets, and use accessors/mutators to interact with instance variables within the class (e.g. they would write [self setName:#"Test"] rather than name = #"Test").
That's not iPhone-specific. Except in init methods and the dealloc method, it's good practice to always use your accessors. The main benefit, especially on the Mac (with Cocoa Bindings), is that using your accessors means free KVO notifications.
The reason why people “declare properties for every single instance variable” is most probably that all of their instance variables are things they want to expose as properties. If they had something they would want to keep private, they would not declare a property for it in the header file. (However, they may make a property for it in a class extension in the implementation file, in order to get the aforementioned free KVO notifications.)
Declaring properties for outlets is overkill, in my opinion. I don't see a point to it. If you don't make a property, the nib loader will set the outlet by direct instance-variable access, which is just fine for that task.
I would suggest that modern development has made a very strong attempt to identify, define and apply best practices.
Among these best practices we find continuity and consistency.
Apart from arguing over use of accessors in init and dealloc methods, accessors should generally be used all the time (inside and outside of a class) for the benefits they offer, including encapsulation, polymorphic var implementations (which both allow for abstracting and refactoring) and to facilitate those best practices of continuity and consistency. The fundamental benefits of an object-orient language come into play when doing things in this way and exploiting the fullness of the language's capabilities. Always being consistent in one's coding is an oft undermentioned benefit, as any senior programmer will usually attest.
You can write like this
//MyClass.h
#class Something;
#interface MyClass : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSArray *items;
#end
//MyClass.m
#interface MyClass()
#property (nonatomic, strong) IBOutlet NSTextField *myTextField;
#property (nonatomic, strong) Something *something;
#end