从Objective C中的头文件隐藏实例变量

iam*_*4de 5 private header declaration objective-c instance-variables

我遇到了一个用Objective C编写的库(我只有头文件和.a二进制文件).在头文件中,它是这样的:

@interface MyClass : MySuperClass 
{ 
    //nothing here
}

@property (nonatomic, retain) MyObject anObject;
- (void)someMethod;
Run Code Online (Sandbox Code Playgroud)

我怎样才能实现同样的目标?如果我尝试在接口的{}内声明没有相应ivar的属性,编译器会给我一个错误.最后,我想在.a中隐藏我的类的内部结构,并将必要的方法暴露给头文件.如何在.m中声明实例变量?类别不允许我添加ivar,只是方法.

bbu*_*bum 14

对于64位应用程序和iPhone应用程序(虽然不在模拟器中),属性合成也能够合成实例变量的存储.

即这是有效的:

@interface MyClass : MySuperClass 
{ 
    //nothing here
}

@property (nonatomic, retain) MyObject *anObject;
@end

@implementation MyClass
@synthesize anObject;
@end
Run Code Online (Sandbox Code Playgroud)

如果您编译32位Mac OS X或iPhone模拟器,编译器将给出错误.

  • 请注意,随着时间的推移,模​​拟器越来越像iOS运行时...例如,这在最新版本中有效. (3认同)

小智 13

您可以使用Cocoa类中使用的相同习语.如果您查看NSString.h中的NSString类接口,您将看到没有声明实例变量.深入了解GNUstep源代码,您将找到诀窍.

请考虑以下代码.

MyClass.h

@interface MyClass : NSObject

// Your methods here
- (void) doSomething;

@end
Run Code Online (Sandbox Code Playgroud)

MyClass.m

@interface MyClassImpl : MyClass {
   // Your private and hidden instance variables here
}
@end

@implementation MyClass

+ (id) allocWithZone:(NSZone *)zone
{
   return NSAllocateObject([MyClassImpl class], 0, zone);
}

// Your methods here
- (void) doSomething {
  // This method is considered as pure virtual and cannot be invoked
  [self doesNotRecognizeSelector: _cmd];          
}

@end

@implementation MyClassImpl

// Your methods here
- (void) doSomething {
  // A real implementation of doSomething
}

@end
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,诀窍在于重载allocWithZone:在您的类中.此代码由NSObject提供的默认alloc调用,因此您不必担心应该使用哪种分配方法(两者都有效).在这样的allocWithZone:中,您可以使用Foundation函数NSAllocateObject()来为MyClassImpl对象而不是MyClass分配内存并初始化isa.之后,用户透明地处理MyClassImpl对象.

当然,您的类的真正实现应由MyClassImpl提供.MyClass的方法应以将消息作为错误接收的方式实现.


use*_*885 6

您可以使用类扩展.类扩展类似于类别但没有任何名称.在Apple文档中,他们只定义私有方法,但实际上您也可以声明内部变量.

MyClass.h

@class PublicClass;

// Public interface 
@interface MyClass : NSObject

@property (nonatomic, retain) PublicClass *publicVar;
@property (nonatomic, retain) PublicClass *publicVarDiffInternal;

- (void)publicMethod;

@end
Run Code Online (Sandbox Code Playgroud)

MyClass.m

#import "PublicClass.h"
#import "InternalClass.h"

// Private interface
@interface MyClass ( /* class extension */ ) 
{
@private
    // Internal variable only used internally
    NSInteger defaultSize;

    // Internal variable only used internally as private property
    InternalClass *internalVar;  

@private 
    // Internal variable exposed as public property 
    PublicClass *publicVar;

    // Internal variable exposed as public property with an other name
    PublicClass *myFooVar;
}

@property (nonatomic, retain) InternalClass *internalVar;

- (void)privateMethod;

@end

// Full implementation of MyClass
@implementation MyClass

@synthesize internalVar;
@synthesize publicVar;
@synthesize publicVarDiffInternal = myFooVar

- (void)privateMethod 
{
}

- (void)publicMethod 
{
}

- (id)init
{
   if ((self = [super init]))
     {
       defaultSize = 512;
       self.internalVar = nil;
       self.publicVar = nil;
       self.publicVarDiffInternal = nil; // initialize myFooVar
     }

   return self;
}
@end
Run Code Online (Sandbox Code Playgroud)

您可以将MyClass.h提供给只有您的公共API和公共属性的任何人.在MyClass.m上,您在类扩展上声明您的成员变量private和public,以及您的私有方法.

像这样,很容易公开公共接口并隐藏详细实现.我在没有任何麻烦的情况下使用了我的项目.


ken*_*ytm 1

不,你不能。但如果您不使用,您可以这样做@property

。H

@interface X : Y {
  struct X_Impl* impl;
}
-(int)getValue;
@end
Run Code Online (Sandbox Code Playgroud)

.米

struct X_Impl {
  int value;
};
...
@implementation X
-(void)getValue {
  return impl->value * impl->value;
}
@end
Run Code Online (Sandbox Code Playgroud)