プロパティは、セッター、ゲッター、およびドット構文アクセサー(インターフェイス変数の非表示)を許可する単なる宣言です。
それ自体はまったく何もしませんが-[myInstance myProperty]
、変数の取得または-[myInstance setMyProperty:]
設定に使用できます(はい、メソッド名はとに自動割り当てされ-setProperty:
ます-property
)。
プロパティを宣言する場合、スレッドロック、アクセス制御、メモリ管理の3つのカテゴリがあります。各カテゴリの修飾子は1つしか選択できません。選択しない場合は、自動的に1つに割り当てられます。
@property (<thread locking>, <access control>, <memory management>) id property;
最初のカテゴリはまたはのいずれatomic
かnonatomic
です。修飾子はatomic
、スレッドセーフを可能にするために、変数に@synchronized(myInstance)ロックを強制します。はnonatomic
同期ブロックを使用せず、スレッドセーフではありません。どちらも使用しない場合は、自動的にに設定されatomic
ます。
2番目のカテゴリは、またはのいずれreadonly
かreadwrite
です。修飾子を使用readwrite
すると、プロパティも変更でき、-setProperty:メソッドの自動生成が可能になります。修飾子を使用する場合readonly
、このメソッドは使用できません-setProperty:
。変数を直接設定するには、オブジェクト内から内部変数を使用する必要があります。
3番目のカテゴリは、、、およびのいずれassign
かretain
ですcopy
。assign
修飾子は、内部オブジェクトポインタがメッセージに渡されたポインタに設定されることを意味します-setProperty:
。モディファイアはretain
渡されたポインタを割り当て、-retain
オブジェクトにを渡します。
copy
モディファイアは、オブジェクトのストレートアップクローンを作成します。これは、メモリ内の新しいアドレスにある新しいオブジェクトへの新しいポインタです。これにより、渡されたオブジェクトを呼び出すことにより、渡されたオブジェクトのコピーへの内部オブジェクトポインタが設定され-copy
ます。デフォルトの修飾子はですassign
。オブジェクトにメモリ管理カテゴリ修飾子を設定しない場合、コンパイラは警告を表示します。これは、オブジェクトのassign
修飾子が(明示的に宣言されていない限り)無視されるためです。
-copyの例については、次を参照してください。
- (void)setProperty:(GXMyObject *)property {
// This points to the original passed object.
GXMyObject *original = property;
// This points to a copy of the passed object.
CGMyObject *copied = [property copy];
// This points to yet another copy of the passed object-
// Independent of the other copies and original.
_property = [property copy];
// The anotherProperty is now different on this copy
// than on the original and the other copies.
_property.anotherProperty = 4;
// This will prove that they are all individual objects.
NSLog(@"%p, %p, %p", original, copied, _property);
}
オプションのメソッド名宣言修飾子があり、次のように使用されます:getter = myCustomPropertyGetter
および(引数を渡す必要があることを示すため、setterメソッド名の最後setter = myCustomPropertySetter:
のコロンが必要です)。:
この後半は、プロパティシンセサイザーまたはダイナマイザーです。プロパティが宣言されると(たとえばmyView
)、次のようになります。
@property (nonatomic, retain) NSView *myView;
セッターとゲッターを自分で定義します。@synthesize
セッターとゲッター。@dynamic
カテゴリまたはメインクラスに存在する、または実行時に追加される可能性があることを示すプロパティ(楽しいアイデアではありません。気を付けてください。実行時の例外が発生する可能性があります)。
最初の例では、メソッドを自分で作成すると、次のようになります。
// In Apple's LLVM 3.1 Compiler, instance variables can be added
// within {} below the @implementation as well as the @interface,
// and in private categories (@interface GXMyClass ()) like before.
@implementation GXMyClass {
// The internal object pointer is prefixed with an _ to avoid name confusions.
NSView *_myView;
}
- (NSView *)myView {
return _myView;
}
- (void)setMyView:(NSView *)myView {
_myView = [myView retain];
}
@end
@synthesize
2番目の例は、ディレクティブを使用して自動合成することです。
@implementation GXMyClass
// In the new Apple LLVM 3.1 Clang compiler, the = operator when used
// next to the @synthesize directive declares an internal private
// variable and automatically sets to that variable.
@synthesize myView = _myView;
// The internal variable name is now myOtherView, because we did not use the
// = operator to assign an internal variable name to the property.
@synthesize myOtherView;
@end
最後の例では、おそらく最も混乱します。@ dynamicディレクティブを使用する必要があるため、カテゴリまたはランタイムメソッドの追加が必要です。
@interface GXMyClass (InternalMethods)
@end
@implementation GXMyClass
// The = assignment operator does not work here.
@dynamic myView;
@end
@implementation GXMyClass (InternalMethods)
- (NSView *)myView {
return [self methodThatReturnsAnNSView];
}
- (void)setMyView:(NSView *)myView {
[self methodThatAcceptsAnNSViewArgument:myView];
}
@end
宣言では、上記の3つの@property
宣言のいずれかが存在する必要があります。それ自体は何もしません。ただし、許可されるのはドット構文アクセサー(プロパティを設定および取得するためのJavaのようなアクセサー)です。
たとえば、を使用してアクセスし、を使用して設定@property (copy) NSString *myName;
できます。-[myObject myName]
-[myObject setMyName:]
myObjectInstance.myName = @"Bob";
これで、を使用して設定し、を使用して取得できますmyObjectInstance.myName
。上記のすべての概念を利用して、次のようなオブジェクトを作成できます。
// The GXBufferQueue is a queue which buffers all requests, till they are read
// asynchronously later. The backing store is an NSMutableArray to which all
// buffer writes are appended to, and from which the first object is pulled and
// returned when the buffer is read to.
@interface GXBufferQueue
@property (nonatomic, readwrite, copy, setter = write:, getter = read) id buffer;
+ (GXBufferQueue *)queue;
@end
@implementation GXBufferQueue {
// This queue is an internal array and is 'tacked on' to the @implementation
// so no others can see it, and it can be marked @private so subclasses cannot
// use it. It is also good code practice to have @interfaces composed of only
// @properties, setters, and getters, rather than expose internal variables.
NSMutableArray *_internalQueue;
}
+ (GXBufferQueue *)queue {
return [[[GXBufferQueue alloc] init] autorelease];
}
- (id)init {
if((self = [super init])) {
_internalQueue = [[NSMutableArray alloc] init];
}
}
- (void)write:(id)buffer {
[_internalQueue addObject:buffer];
}
- (id)read {
if(!(_internalQueue.count > 0)) return nil;
id buffer = [_internalQueue objectAtIndex:0];
[_internalQueue removeObjectAtIndex:0];
return buffer;
}
@end
注:このコードはテストされていません。GXBufferQueueができたので、次のすべてが機能します。
GXBufferQueue *queue = [GXBufferQueue queue];
// Option One: using the traditional message syntax:
[queue write:@"This will be now added to the buffer."];
NSLog(@"Now the string written to the queue will be read \
and removed from the queue, like a stack pop. ", [queue read]);
// Option Two: using the new dot-syntax accessors:
queue.buffer = @"As clunky as this looks, it works the same as above.";
NSLog(@"These lines work just the same as the ones above: ", queue.buffer);
ご覧のとおり、プロパティには多くの可能性があり、変数の宣言だけでなく、プロパティを使用して実行できることもたくさんあります。質問やコミュニティが投稿に追加/修正したいことがある場合は、コメントを残してください!:D