0

次の方法でNSMutable配列を作成しています。

-(NSArray*)createArrayFromString:(NSString*)str
{
    NSArray *arr = [str componentsSeparatedByString:@" "]; 
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[arr count]];

    for(NSString *s in arr){
        if([s length]>0){
            [result addObject:[s retain]];
        }
    }
    return (NSArray*) result;
}

受信した配列要素をChapterオブジェクトのプロパティresRefsに配置する呼び出しメソッドは次のとおりです。

-(Chapter*)createChapter:(CXMLNode*)node
    {
        Chapter *chapter = [[Chapter alloc] init];
        chapter._id = [[(CXMLElement*)node  attributeForName:@"id"] stringValue];
        chapter.title = [[(CXMLElement*)node attributeForName:@"title"] stringValue];
        chapter.text = [node stringValue];
        [chapter.pids addObjectsFromArray:[self createArrayFromString:[[(CXMLElement*)node attributeForName:@"pids"]stringValue]]];
        [chapter.resRefs addObjectsFromArray:[self createArrayFromString:[[(CXMLElement*)node attributeForName:@"resRefs"]stringValue]]];
        return chapter;
    }

ここに質問があります:

保持呼び出しなし

[result addObject:[s retain]];

ViewController(EXC_BAD_ACCESS)からNSString要素にアクセスできません

ここでretainを正しく使用していますか?

編集:

かわった

 [[result addObject:s] retain];

の中へ

 [result addObject:[s retain]];

2行目は元々私のコードにありました。この質問を投稿するときに、保持を削除して間違った場所に挿入し直しました。それでも、ここで保持することは機能しますが、除外することは機能しません。

編集2:

アナライザー(CMD + SHIFT + B)を検出し、いくつかのメモリリークを検出し、それらを削除すると、EXC_BAD_ACCESSがなくなりました。皆様のご協力に感謝します!

4

3 に答える 3

8
[result addObject:s]

何も返さないため、保持するものはありません。

オブジェクト s は配列によって保持されます。

NSMutableArray *result = [NSMutableArray arrayWithCapacity:[arr count]];

これはローカル オブジェクトであるため、保持されることはありません。

メモリ ルールを理解する必要があります。命名規則によると、名前が「alloc」、「new」、「copy」、または「mutableCopy」で始まるメソッドは、保持されたオブジェクトを提供する必要があります。したがって、メソッドはそれで開始されず、自動解放された(=保持されていない)オブジェクトを返すため、問題ないようです。保持するかしないかは、発信者の義務です。

また、補足:

return (NSArray*) result;

NSMutableArray を NSArray に変換しません。キャストは、コンパイラが何を期待すべきかを伝えるだけです。NSMutableArray は NSArray であるため、コンパイラはすでにそれを認識しています。そして実際には、キャストはメソッドのシグネチャのリターン定義によってすでに定義されています。


メソッドで何か他のことをしていますか?そうでない場合 — 私はあなたを苦しめたくありません — あなたがNSArray *arr = [str componentsSeparatedByString:@" "];望むものと同じように、あなたは本当にそれを必要としません. @" "本当に呼び出し元からを因数分解したい場合は、 のように呼び出された上でカテゴリを使用することを検討する必要があります。NSStringcomponentsSeparatedByBlank

それは次のように見える可能性があります

@interface NSString (Separation)
-(NSArray *)componentsSeparatedByBlank;
@end

@implementation NSString (Separation)
-(NSArray *)componentsSeparatedByBlank
{
    return [self componentsSeparatedByString:@" "];
}
@end

または空白文字セットを使用:

-(NSArray *)componentsSeparatedByWhiteSpace
{
    NSArray *array = [self componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
    return [array filteredArrayUsingPredicate: [NSPredicate predicateWithFormat:@"SELF != ''"]];
}
于 2012-06-14T12:14:51.567 に答える
3

ここで保持を正しく使用していますか?

いいえ。NSMutableArray は、追加したオブジェクトを保持します。その後、remove を呼び出したとき、または配列が解放されたときにそれらを解放します。ここで保持を呼び出す必要はありません。ただし、これが EXC_BAD_ACCESS を経験している理由ではありません

vikingosegundo が言ったように、addObject は何も返さないため、retain を呼び出すと EXC_BAD_ACCESS が返されます。

あなたがやろうとしていることの正しい構文は次のとおりです(注:上記で説明したようにこれを行う必要はありません)

[result addObject:[s retain]]; // BAD

というわけで、結論だけ言うと

[result addObject:s]; // GOOD - s is retained by result

EDIT *ポスターの元のコードを書き直しました...

-(NSArray*)arrayFromString:(NSString*)str // Note naming convention of method
{
    NSMutableArray *arr = [str componentsSeparatedByString:@" "]; // Won't give you any 0 length strings

// Do some other character/validation checks here?

    return arr; // returns autoreleased NSMutableArray complying to naming convention
}

文字列を返す前に何もしたくない場合は、 createChapters メソッドでこれを使用できます...

NSArray *arr = [[[(CXMLElement*)node attributeForName:@"pids"] stringValue] componentsSeparatedByString:@" "];
[chapter.pids addObjectsFromArray:arr];

メモリ管理と命名規則をよく読んでください。将来的に多くの時間を節約できます。

于 2012-06-14T12:21:54.620 に答える
2
[[result addObject:s] retain]; 

ボイドメソッドです。これは、次のような値を返さないことを意味します。

- (NSString)methodThatReturnsString;

でしょう。ボイドは基本的に何も意味しないため、何も保持しないボイドを保持しています。ただし、配列を追加するオブジェクトは配列によって保持されます。

于 2012-06-14T12:17:18.430 に答える