How should private and public members be implemented in objective-c?

16,901

Solution 1

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:


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)

Solution 2

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.

Solution 3

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

Share:
16,901

Related videos on Youtube

Centurion
Author by

Centurion

Dreams coming true through software craftsmanship.

Updated on July 21, 2022

Comments

  • Centurion
    Centurion almost 2 years

    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.

    • mostafa tourad
      mostafa tourad over 12 years
      This question seems to be very subjective and impossible to answer the right way.
    • Centurion
      Centurion over 12 years
      The question is very straightforward - how should private and public members be implemented in objective-c, and where I could find Apple strict voice on that.
    • mostafa tourad
      mostafa tourad over 12 years
      I beg to differ but will not go deeper into the discussion. As a hint for proving my claim, you noted yourself that e.g. the Stanford courses recommend using properties everywhere.
    • Centurion
      Centurion over 12 years
      @Till, I'm just looking for solid source of prove about how Apple would like us to design our classes. I have cited Stanford course because their teachers have some relations with Apple engineers (there were even several teachers from ex Apple devs) and their course was globally accepted, so I'm using the course as one of solid sources. However, related statements in Apple docs would be much more desirable.
    • Hot Licks
      Hot Licks over 12 years
      There is no 100% sure way to implement private members in Objective-C. The very nature of a "duck typed" language is that you can do with an object whatever it responds to (and then some), so, absent a capability mechanism (which Objective-C also lacks), every interface is effectively public (even though you may have to "cheat" a bit to access some of them).
    • Hot Licks
      Hot Licks over 12 years
      (Also note that strict, enforceable private/public access is not critical to good OO design. Though it's nice if you can, you shouldn't need to rely on language properties to enforce good programming practices.)
  • Tommy
    Tommy over 12 years
    Some pedant will point out: those aren't strictly private because the getters and setters can still be used by other code if it's willing to brave a compiler warning, but as far as I'm concerned a compiler warning is sufficient to warn others off. This is exactly the way (well, give or take your trailing underscores) I require instance variable declaration in my team — the rule I apply is that anything in the header file is public by definition.
  • Centurion
    Centurion over 12 years
    @Tommy: at my work, some guys argued, why we need to declare and use properties for private members. They said we should use pure instance variables and use them directly in class code. The motivation to do that was there's some processing overhead when using setter instead of releasing old value manually and assigning new val directly to ivar. Just curious are there any Apple "recommended" like statements on that?
  • Centurion
    Centurion over 12 years
    Yes, there are such keywords as public, private and protected, but they do not limit the scope during the runtime. I have performed some tests, and I can say that in objective-c all members are pretty public. You can find the post about my experiment here: stackoverflow.com/questions/6122398/…
  • albertamg
    albertamg over 12 years
    @Centurion You can use "private" properties to make memory management easier: "Sometimes it might seem tedious or pedantic, but if you use accessor methods consistently, the chances of having problems with memory management decrease considerably. If you are using retain and release on instance variables throughout your code, you are almost certainly doing the wrong thing."
  • vikingosegundo
    vikingosegundo over 12 years
    I added a link for redeclaration of public readonly properties — very handy.
  • Tommy
    Tommy over 12 years
    @Centurion: If you declare instance variables via properties in a category internal to the implementation class then you benefit because you're not publishing that information but you actually get both the 'pure' instance variable and the setter/getter route. In vikingosegundo's case, the pure instance variables will be called amount_ and colors_. Accessing those directly will cost exactly the same as if you'd put them in the @interface declaration. Though I'd still advocate the getters/setters as default usage since the cost is tiny and the memory management gains are significant.
  • Steven Kramer
    Steven Kramer almost 12 years
    Thanks for that, very useful and not widely documented.
  • Centurion
    Centurion almost 11 years
    @vikingosegundo nice update regarding declaration of ivars in class implementation block. I should consider changing my current habit to this one :)