おそらく、接頭辞 で始まらdeepCopy
ないためです。copy
そのため、次のようなもの (またはそのようなもの)に変更してcopyWithDeepCopiedValues
、アナライザーがフラグを立てるかどうかを確認することをお勧めします。
アップデート
Alexsander が指摘したように、属性を使用して参照カウントの意図を示すことができます。これは(IMO)ルールの例外であり、めったに使用されないはずです。個人的には、壊れやすいため、objc メソッドの属性は使用しません。
これまでに使用した唯一の属性はconsume
であり、これらの属性を使用するたびに、静的に型指定されたコンテキスト (C 関数、C++ 関数およびメソッドなど) で使用されています。
可能であれば属性を避けるべき理由:
1) プログラマーのために慣習を守りましょう。コードがより明確になり、ドキュメントを参照する必要がなくなりました。
2) アプローチが脆弱です。参照カウントの不均衡が引き続き発生する可能性があり、属性を使用して、属性の競合によるビルド エラーが発生する可能性があります。
次のケースはすべて、ARC を有効にして構築されています。
ケース #1
#import <Foundation/Foundation.h>
@interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
@end
@implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:@"MONType"];
return ret;
}
@end
int main (int argc, const char * argv[])
{
@autoreleasepool {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:@"NSAttributedString"];
}
else {
obj = [MONType new];
}
NSLog(@"Result: %@, %@", obj, [obj string]);
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
このプログラムは次のエラーを生成します: error: multiple methods named 'string' found with mismatched result, parameter type or attributes
.
すばらしい、コンパイラはこれらの問題を防ぐためにできることをしています。つまり、属性の競合により、翻訳に基づくエラーが発生する可能性があります。重要なコードベースが組み合わされて属性が競合すると、エラーを修正してプログラムを更新する必要があるため、これは悪いことです。これはまた、単に他のライブラリを翻訳単位に含めると、属性が使用されている場合に既存のプログラムが壊れる可能性があることを意味します。
ケース#2
Header.h
extern id NewObject(void);
ヘッダー.m
#import <Foundation/Foundation.h>
#import "Header.h"
@interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
@end
@implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:@"-[MONType string]"];
return ret;
}
@end
id NewObject(void) {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:@"NSAttributedString"];
}
else {
obj = [MONType new];
}
return obj;
}
main.m
#import <Foundation/Foundation.h>
#import "Header.h"
int main (int argc, const char * argv[])
{
@autoreleasepool {
for (size_t idx = 0; idx < 8; ++idx) {
id obj = NewObject();
NSLog(@"Result: %@, %@", obj, [obj string]);
}
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
Ok。これはただ悪いです。必要な情報が翻訳単位で利用できなかったため、リークが発生しました。リークレポートは次のとおりです。
leaks Report Version: 2.0
Process 7778: 1230 nodes malloced for 210 KB
Process 7778: 4 leaks for 192 total leaked bytes.
Leak: 0x1005001f0 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500320 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500230 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
Leak: 0x100500390 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
注:使用したため、カウントが異なる場合がありますrandom()
これは、 が からMONType
見えないためmain()
、コンパイラが ARC プロパティを、現在の TU から見えるメソッドにバインドしたことを意味します (つまりstring
、Foundation の宣言から、すべて規則に従います)。その結果、コンパイラはそれを誤り、プログラムにリークを導入することができました。
ケース 3
同様のアプローチを使用して、負の参照カウントの不均衡 (時期尚早のリリース、またはメッセージ ゾンビ) を導入することもできました。
注: ケース #2 で、参照カウントの不均衡を達成する方法が既に示されているため、コードは提供されていません。
結論
属性を使用するのではなく、規則に従うことで、これらの問題をすべて回避し、読みやすさと保守性を向上させることができます。
会話を ARC 以外のコードに戻す: 属性を使用すると、手動のメモリ管理が難しくなり、プログラマーが読みやすくなり、プログラマーを支援するツール (コンパイラー、静的解析など) が使用しにくくなります。ツールがそのようなエラーを検出できないほどプログラムが適切に複雑な場合は、設計を再検討する必要があります。これらの問題をデバッグするのは、あなたや他の誰かにとって同じように複雑になるからです。