6

Objective C で書かれたライブラリに出会いました (ヘッダー ファイルと .a バイナリしかありません)。ヘッダー ファイルでは、次のようになります。

@interface MyClass : MySuperClass 
{ 
    //nothing here
}

@property (nonatomic, retain) MyObject anObject;
- (void)someMethod;

どうすれば同じことを達成できますか? インターフェイスの {} 内に対応する ivar を持たないプロパティを宣言しようとすると、コンパイラでエラーが発生します。最終的には、クラスの内部構造を .a 内に隠し、必要なメソッドだけをヘッダー ファイルに公開したいと考えています。.m 内でインスタンス変数を宣言するにはどうすればよいですか? カテゴリでは ivar を追加できず、メソッドのみを追加できます。

4

10 に答える 10

14

64 ビット アプリケーションと iPhone アプリケーション (シミュレーターにはありません) の場合、プロパティ合成はインスタンス変数のストレージを合成することもできます。

つまり、これは機能します:

@interface MyClass : MySuperClass 
{ 
    //nothing here
}

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

@implementation MyClass
@synthesize anObject;
@end

32 ビット Mac OS X または iPhone シミュレーター用にコンパイルすると、コンパイラーはエラーを返します。

于 2010-01-20T18:36:40.907 に答える
13

Cocoa のクラスで使用されているのと同じイディオムを使用できます。NSString.h の NSString クラス インターフェイスを見ると、インスタンス変数が宣言されていないことがわかります。GNUstep のソース コードをさらに深く掘り下げると、その秘訣がわかります。

次のコードを検討してください。

MyClass.h

@interface MyClass : NSObject

// Your methods here
- (void) doSomething;

@end

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

ご覧のとおり、トリックはクラスでallocWithZone:をオーバーロードすることにあります。このコードは、 NSObjectによって提供されるデフォルトのallocによって呼び出されるため、どの割り当てメソッドを使用する必要があるかを心配する必要はありません (どちらも有効です)。このようなallocWithZone:では、 Foundation 関数NSAllocateObject()を使用してメモリを割り当て、 MyClassの代わりにMyClassImplオブジェクトのisaを初期化できます。その後、ユーザーはMyClassImplオブジェクトを透過的に処理します。

もちろん、クラスの実際の実装はMyClassImplによって提供されます。MyClassのメソッドは、メッセージの受信をエラーと見なす方法で実装する必要があります。

于 2010-04-05T15:37:36.310 に答える
7

クラス拡張機能を使用できます。クラス拡張はカテゴリに似ていますが、名前はありません。Apple のドキュメントでは、プライベート メソッドを定義しているだけですが、実際には内部変数を宣言することもできます。

MyClass.h

@class PublicClass;

// Public interface 
@interface MyClass : NSObject

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

- (void)publicMethod;

@end

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

公開 API と公開プロパティだけで MyClass.h を誰にでも渡すことができます。MyClass.m では、メンバー変数のプライベートとパブリック、およびプライベート メソッドをクラス拡張で宣言します。

このように、パブリック インターフェイスを公開し、詳細な実装を隠すのは簡単です。私は自分のプロジェクトで問題なく使用しました。

于 2011-09-09T10:11:42.437 に答える
2

私が見てきたドキュメントによると、問題はありません。インスタンス変数を非表示にするために必要なのは、@implementation セクションの先頭の { ... } 内で宣言することだけです。ただし、私は Objective C に比較的慣れていないため、何かを誤解している可能性があります。言語が変更された可能性があります。XCode 4.2 を使用して iPad 用のコードを作成し、実際にこのシステムを試してみましたが、問題なく動作するようです。

このアイデアのソースの 1 つは、http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocDefiningClasses.htmlにある Apple 開発者ドキュメントで、次のパターンが示されています。

@実装クラス名

{

// Instance variable declarations.

}

// メソッド定義。

@終わり

于 2012-01-16T18:46:34.667 に答える
1

いいえ、できません。ただし、使用していない場合はこれを行うことができます@property

.h

@interface X : Y {
  struct X_Impl* impl;
}
-(int)getValue;
@end

.m

struct X_Impl {
  int value;
};
...
@implementation X
-(void)getValue {
  return impl->value * impl->value;
}
@end
于 2010-01-20T18:28:24.700 に答える
1

2 つの可能性:

  1. bbum が示唆したように、インスタンス変数を合成する最新のランタイムの機能を利用している可能性があります。
  2. プロパティは、そのクラスに基になるインスタンス変数を持っていない可能性があります。プロパティは、インスタンス変数との 1 対 1 のマッピングを持つとは限りません。
于 2010-01-20T18:43:44.430 に答える
0

マクロトリックはどうですか?

以下のコードをテストしました

  • dylibsでテストしました-正常に動作しました
  • サブクラス化をテストしました-警告!壊れます、私はこれがトリックをそれほど役に立たないものにすることに同意します、しかしそれでもそれはObjCがどのように機能するかについていくらか教えてくれると思います...

MyClass.h

@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

MyClass.m

// 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
于 2010-01-20T18:58:15.020 に答える
0

これをしないでください。ただし、ランタイムには、いつでもclass_addIvar を使用してivar を追加できることに注意してください。

于 2010-04-05T15:45:06.013 に答える
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 にかなり慣れていないので、経験豊富な人のアドバイスをいつでも利用できます。

于 2010-12-02T18:56:25.080 に答える
-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
于 2011-03-31T21:19:16.467 に答える