わかりました、私は経験豊富な C++ 開発者です。かなり充実した Cocoa アプリケーションを構築しようとしながら、その場で Objective-C を学んでいます。このプロジェクトの準備をしている間に、Cocoa を使っていくつかの単純なアプリを作成しましたが、ほとんどの概念をうまく処理できたと思います。
メモリ管理のパラダイムは私にはまだ少し漠然としていますが、メモリ アナライザーを使用して構築し、問題をすぐに発見できるようにしています。ドキュメントの。
だからここに私の質問があります。
performSelector:onThread:withObject:waitUntilDone:
メソッドを使用して相互に通信する 2 つのスレッドがあります。withObject:
これらは、メソッドのパラメーターとして渡されたオブジェクトを相互に渡します。
サンプルコードは次のとおりです。
- (BOOL)postMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread.
[self performSelectorOnMainThread:@selector(messageHandler:) withObject:message waitUntilDone:NO];
// message is released here and retain count will be +1 or 0 depending on thread ordering
[message release];
return YES;
}
return NO;
}
- (BOOL)sendMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data messageResult:(void**)result
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread. retain count will be +1 on return
[self performSelectorOnMainThread:@selector(messageHandler:) withObject:message waitUntilDone:YES];
if(result)
*result = [message result];
// message is released here and retain count will be 0 triggering deallocation
[message release];
return YES;
}
return NO;
}
- (void)messageHandler:(Message*)message
{
// message will have a retain count of +1 or +2 in here based on thread execution order
if(message)
{
switch ([message messageId])
{
case
...
break;
default:
...
break;
}
// message is released here bringing retain count to +1 or 0 depending on thread execution ordering
[message release];
}
}
アナライザーは、でMessage
割り当てられたオブジェクトのリークの可能性について不平を言っていますが、オブジェクトは で解放されています。コードは正しく実行され、リークもありません。アナライザーは、オブジェクトが別のスレッドで解放されていることを認識できていないだけだと思います。postMessage:
sendMessage:
messageHandler:
Message
メソッドではなく post/send メソッドで 2 番目の保持を行う理由を疑問に思っている場合はmessageHandler:
、postMessage:
メソッドが非同期であることを意図しており、post メソッドではin[message release]
の前にメソッドが実行される可能性があるためです。無効なオブジェクト。メソッドの場合は同期であるため、それを行うとうまく機能します。[message retain]
messageHandler:
sendMessage:
それで、メモリアナライザーを満足させるより良い方法はありますか? それとも、オブジェクトが実際に解放されているというヒントをメモリ アナライザーに与える方法でしょうか?
アップデート:
トーリーは以下の回答を提供しましたが、私は彼が提案したこととは異なる何をしなければならなかったかを明確にしたかった.
messageHandler:
彼は、以下のように私のメソッドで属性を使用することを提案しました
- (void)messageHandler:(Message*) __attribute__((ns_consumed)) message;
オブジェクトが渡されてperformSelector:
おり、アナライザーはそれが渡されているのを認識していないため、これはうまく機能しませんでしたmessageHandler:
performSelector:
呼び出しは私ではなく Cocoa によって定義されているため、属性を追加することはできません。
これを回避するには、次のように呼び出しをラップしperformSelector:
ます。
- (void)myPerformSelector:(SEL)sel onThread:(NSThread*)thread withObject:(id) __attribute__((ns_consumed)) message waitUntilDone:(BOOL)wait;
{
[self performSelector:sel onThread:thread withObject:message waitUntilDone:wait];
}
その後、ラッパー関数を呼び出すことができ、アナライザーは属性を確認し、バランスの取れていない保持/解放のペアについて文句を言うことはありません。結局、警告を取り除くためだけに余分な間接化が好きではなかったので、以下のコメントで説明されているようにプリプロセッサを使用しました。しかし、この方法を使用すると便利な状況を見ることができました。