我遇到了一个用Objective C编写的库(我只有头文件和.a二进制文件)。 在头文件中,它是这样的:
@interface MyClass : MySuperClass
{
//nothing here
}
@property (nonatomic, retain) MyObject anObject;
- (void)someMethod;
我怎样才能达到同样的目的?如果我尝试在接口的{}内声明没有相应ivar的属性,编译器会给我一个错误。最后,我想在.a中隐藏我的类的内部结构,并将必要的方法暴露给头文件。如何在.m中声明实例变量?类别不允许我添加ivar,只是方法。
答案 0 :(得分:14)
对于64位应用程序和iPhone应用程序(虽然不在模拟器中),属性合成也能够合成实例变量的存储。
即。这有效:
@interface MyClass : MySuperClass
{
//nothing here
}
@property (nonatomic, retain) MyObject *anObject;
@end
@implementation MyClass
@synthesize anObject;
@end
如果编译32位Mac OS X或iPhone模拟器,编译器将发出错误。
答案 1 :(得分:13)
您可以使用Cocoa类中使用的相同习语。如果您查看NSString.h中的NSString类接口,您将看到没有声明实例变量。深入了解GNUstep源代码,您将找到诀窍。
请考虑以下代码。
@interface MyClass : NSObject
// Your methods here
- (void) doSomething;
@end
@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
正如您所看到的,诀窍在于在您的课程中重载 allocWithZone:。此代码由 NSObject 提供的默认 alloc 调用,因此您不必担心应该使用哪种分配方法(两者都有效)。在这样的 allocWithZone:中,您可以使用Foundation函数 NSAllocateObject()来分配内存并为 MyClassImpl isa > object而不是 MyClass 。之后,用户透明地处理 MyClassImpl 对象。
当然,您的类的真正实现应由 MyClassImpl 提供。 MyClass 的方法应以将消息作为错误接收的方式实现。
答案 2 :(得分:6)
您可以使用类扩展。类扩展类似于类别但没有任何名称。在Apple文档中,他们只定义私有方法,但实际上您也可以声明内部变量。
@class PublicClass;
// Public interface
@interface MyClass : NSObject
@property (nonatomic, retain) PublicClass *publicVar;
@property (nonatomic, retain) PublicClass *publicVarDiffInternal;
- (void)publicMethod;
@end
#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
您可以将MyClass.h提供给只有您的公共API和公共属性的任何人。在MyClass.m上,您在类扩展上声明您的成员变量private和public以及您的私有方法。
像这样,很容易公开公共接口并隐藏详细实现。我在没有任何麻烦的情况下使用了我的项目。
答案 3 :(得分:2)
根据我一直在看的文档,没有问题。隐藏实例变量所需要做的就是在{...}内的@implementation部分的开头声明它们。但是,我是Objective C的相对新手,我有可能误解了一些东西 - 我怀疑语言已经改变了。我实际上尝试过这个系统,使用XCode 4.2,为iPad构建代码,它似乎工作正常。
我的这个想法的一个来源是http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocDefiningClasses.html上的Apple开发人员文档,它提供了这种模式:
@implementation ClassName
{
// Instance variable declarations.
}
//方法定义。
@end
答案 4 :(得分:1)
不,你不能。但是,如果您不使用@property
:
@interface X : Y {
struct X_Impl* impl;
}
-(int)getValue;
@end
struct X_Impl {
int value;
};
...
@implementation X
-(void)getValue {
return impl->value * impl->value;
}
@end
答案 5 :(得分:1)
两种可能性:
答案 6 :(得分:0)
宏诡计怎么样?
测试了以下代码
@interface MyClass : NSObject {
#ifdef MYCLASS_CONTENT
MYCLASS_CONTENT // Nothing revealed here
#endif
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, assign) int extra;
- (id)initWithString:(NSString*)str;
@end
// Define the required Class content here before the #import "MyClass.h"
#define MYCLASS_CONTENT \
NSString *_name; \
int _extra; \
int _hiddenThing;
#import "MyClass.h"
@implementation MyClass
@synthesize name=_name;
@synthesize extra=_extra;
- (id)initWithString:(NSString*)str
{
self = [super init];
if (self) {
self.name = str;
self.extra = 17;
_hiddenThing = 19;
}
return self;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
@end
答案 7 :(得分:0)
不要这样做,但我觉得应该注意运行时能够使用class_addIvar
添加ivars 你想要的答案 8 :(得分:0)
我能够在我的图书馆中执行以下操作:
myLib.h:
@interface MyClass : SomeSuperClass <SomeProtocol> {
// Nothing in here
}
- (void)someMethods;
@end
myLib.m
@interface MyClass ()
SomeClass *someVars;
@property (nonatomic, retain) SomeClass *someVars;
@end
@implementation MyClass
@synthesize someVar;
- (void)someMethods {
}
@end
当然,协议是可选的。我相信这也使你的所有实例变量都是私有的,虽然我不是100%肯定的。对我而言,它只是我的静态库的一个接口,所以它并不重要。
无论如何,我希望这会帮助你。对于其他阅读此内容的人,请告诉我一般情况下这是不好的还是有任何不可预见的后果。我自己对Obj-C很新,所以我总能使用经验丰富的建议。
答案 9 :(得分:-1)
我不认为以下代码中写的代码是按预期工作的。 扩展类中定义的“SomeClass * someVars”不是MyClass的实例变量。我认为这是一个C全局变量。如果您合成someVars,您将收到编译错误。并且self.someVars也不起作用。
<强> myLib.h 强>
@interface MyClass : SomeSuperClass <SomeProtocol> {
// Nothing in here
}
- (void)someMethods;
@end
<强> myLib.m 强>
@interface MyClass ()
SomeClass *someVars;
@property (nonatomic, retain) SomeClass *someVars;
@end
@implementation MyClass
@synthesize someVar;
- (void)someMethods {
}
@end