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

前端 未结 3 1606
孤城傲影
孤城傲影 2020-12-13 14:32

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 pr

相关标签:
3条回答
  • 2020-12-13 14:46

    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

    0 讨论(0)
  • 2020-12-13 14:57

    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)

    0 讨论(0)
  • 2020-12-13 14:59

    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.

    0 讨论(0)
提交回复
热议问题