2

私はここで難しい問題を抱えています。何か助けていただければ幸いです =)

私は、Objective-C/iPhone/Cocoa を初めて使用する経験豊富な開発者です。

NSMutableArray をパラメーターとして渡すことができるクラス コントローラーを作成したいと考えています。

次に、次のようになります。

selTimeIntController = [[SingleSelectPickerViewController alloc] initWithSettings: listOfIntervals :kAlarmIntervalStr :myDataHolder.alarmInterval];
[self.navigationController pushViewController: selTimeIntController animated: YES];
[selTimeIntController release];

この listOfIntervals は、すでに alloc/init NSMutableArray* です。

私の SingleSelectPickerViewController には、次のものがあります。

-(id)initWithSettings:(NSMutableArray*)sourceArray :(NSString*)viewCurrentValue :(NSString*)viewTitle {

    if(self = [self initWithNibName: kNibName bundle: [NSBundle mainBundle]]) {

            listOfIntervals = [NSMutableArray arrayWithArray: (NSMutableArray*)sourceArray];
            currentValue    = [[NSString alloc] initWithString: viewCurrentValue];
            title           = [[NSString alloc] initWithString: viewTitle];
    }

    return self;
}

デバッグを通じて、SingleSelectPickerViewController で作成されている listOfIntervals を確認できます。

ここに、SingleSelectPickerViewController の dealloc があります。

- (void)dealloc {
    [super dealloc];

    [listOfIntervals release];
    [currentValue    release];
    [title           release];
}

しかし、SingleSelectViewController をインスタンス化するたびに、直後に次のスタックで EXEC_BAD_ADDRESS を受け取ります。

#0  0x96132688 in objc_msgSend ()
#1  0x00003ee2 in -[SingleSelectPickerViewController tableView:numberOfRowsInSection:] (self=0xd38940, _cmd=0x319a6bc0, tableView=0x102e000, section=0) at /Users/Cadu/iPhone/myApp/Classes/SingleSelectPickerViewController.m:115
#2  0x30a86bb4 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#3  0x30a8879b in -[UITableViewRowData rectForFooterInSection:] ()
#4  0x30a883c7 in -[UITableViewRowData heightForTable] ()
#5  0x3094e8e6 in -[UITableView(_UITableViewPrivate) _updateContentSize] ()
#6  0x30940a7d in -[UITableView noteNumberOfRowsChanged] ()
#7  0x3094a2a0 in -[UITableView reloadData] ()
#8  0x30947661 in -[UITableView layoutSubviews] ()
#9  0x00b41d94 in -[CALayer layoutSublayers] ()
#10 0x00b41b55 in CALayerLayoutIfNeeded ()
#11 0x00b413ae in CA::Context::commit_transaction ()
#12 0x00b41022 in CA::Transaction::commit ()
#13 0x00b492e0 in CA::Transaction::observer_callback ()
#14 0x30245c32 in __CFRunLoopDoObservers ()
#15 0x3024503f in CFRunLoopRunSpecific ()
#16 0x30244628 in CFRunLoopRunInMode ()
#17 0x32044c31 in GSEventRunModal ()
#18 0x32044cf6 in GSEventRun ()
#19 0x309021ee in UIApplicationMain ()
#20 0x000020d8 in main (argc=1, argv=0xbffff0b8) at /Users/Cadu/iPhone/MyApp/

何が起こっているのか分かりますか?

4

4 に答える 4

7

質問のタイトルは「メモリリーク」です。質問のすべてが「クラッシャー」を示しています。これはクラッシャーであり、メモリ リークではありません。または、少なくとも、クラッシャーを修正するまで、メモリ リークがあるかどうかはわかりません。

クラッシュの最も可能性の高い原因は、listOfIntervals インスタンス変数の不適切な管理です。

listOfIntervals = [NSMutableArray arrayWithArray: (NSMutableArray*)sourceArray];

具体的には、次のようにする必要があります。

listOfIntervals = [[NSMutableArray arrayWithArray: sourceArray] retain];

Mike が上で示したように、変更可能なコレクション参照を渡すのはおそらく悪い考えです。sourceArrayあなたのクラスの下で変わったらどうなりますか?それに対処する準備はできていますか?

より一般的なイディオムは、NSArray* を取るメソッドを宣言してから、配列をコピーすることです。

listOfIntervals = [sourceArray mutableCopy]; // or -copy, if you don't need it to be mutable

(1)(NSMutableArray*)キャストは不要でした。害を知っていましたが、必要がないのになぜそれを持っているのですか?

(2) listOfIntervals を保持する必要があります。+arrayWithArray: は自動解放された配列を作成するため、配列はreleasedオブジェクトの初期化後に作成され、クラッシュが発生します。

(3) -copy & -mutableCopy は保持されたオブジェクトを返します。-retain を呼び出す必要はありません。

-deallocただし、メソッドを修正する必要もあります。

- (void)dealloc {
    // move this [super dealloc];

    [listOfIntervals release];
    [currentValue    release];
    [title           release];
    [super dealloc]; // to here
}

[super dealloc] 常に最後でなければなりません。-dealloc について魔法はありません。したがって、最初にその呼び出しを行うことで、インスタンスにそれ自体の割り当てを解除するように指示し、次にインスタンス変数を調べてクリーンアップします。これは、2 回目のクラッシュ (または予期しない動作) につながる可能性があります。

全体として、メモリ管理ガイドラインを読み直すことをお勧めします。

http://developer.apple.com/iPhone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

于 2009-09-14T23:19:17.523 に答える
0
  1. sourceArrayはどうですか?どこかに保持されていますか?スコープを超えて使用するには、割り当てられたオブジェクトを保持する必要があります。そうしないと、自動解放されます。配列を再度作成しなくても、クラスでその単純な参照を使用できます。

または、できます

listOfIntervals = [[NSMutableArray arrayWithArray:(NSMutableArray *)sourceArray]保持];

それを使用してリリースします。

  1. 上記の答えは、すべてのクラス割り当てを解放する前に[superdealloc]を呼び出すことに気づきました。[superdealloc]を最後に呼び出す必要があります。

  2. Cocoaのメモリ管理、特にalloc/retain関数の使用に関する便利なリンクがたくさんあります。これは、Cocoa/iPhoneプログラミングの非常に重要な部分です。たとえば、これを参照してください:Cocoaでのメモリ管理、または単にグーグルで

お役に立てば幸いです。

于 2009-09-14T14:41:54.727 に答える
0

私は Mac プログラミングは初めてですが、dealloc メソッドの順序が間違っていると思います。

そのはず:

- (void)dealloc {
    [listOfIntervals release];
    [currentValue    release];
    [title           release];

    [super dealloc];
}

これで問題が解決するとは思いませんが、修正する必要があります。

また、あなたがここで何をしているのかわかりません:

if(self = [self initWithNibName: kNibName bundle: [NSBundle mainBundle]]) {
    //...
}

私はそれがすべきだと思います:

if ( ! [super initWithNibName: kNibName bundle: [NSBundle mainBundle]] ) {

       return nil;
}

//...
于 2009-09-14T14:18:57.597 に答える
0

これについては、基本に立ち返る必要があります。


問題 1: ミュータブルな基盤オブジェクトを渡しています

これはほとんどの場合、設計が悪いことを示しています。Cocoa/CocoaTouch を見ると、パラメーターとして渡されたり返されたりする可変クラスの使用はほとんどないことがわかります。そうするのは、ほとんどの場合、パフォーマンスの制約によるものです。

なぜ悪いのですか?呼び出しを行った後、2 つ以上のオブジェクトがすべて同じ変更可能なオブジェクトを共有することは非常に簡単です。1 人が変更を加えた場合、他の人はそれを知る方法がなく、後で非常に奇妙な動作を引き起こす可能性があります。デバッグするのは楽しくありません。


問題 2: 配列を保持していない

これはメモリ管理の基本であり、深入りする前に必ず理解しておく必要があります。Apple の方が私よりもうまく説明できるかもしれませんが、要約すると次のようになります。

与えられた範囲外のオブジェクトにアクセスする必要がある場合は、それを保持してください。後で完了したら解放します。

ここで行っているのは、自動解放された配列をlistOfIntervalsインスタンス変数に割り当てることです。もちろん、後で解放されて割り当てが解除され、次にアクセスしようとするとアプリが爆発します。代わりに、正しいコードは次のとおりです。

- (id)initWithIntervals:(NSArray *)sourceArray
           currentValue:(NSString *)viewCurrentValue
                  title:(NSString *)viewTitle
{
  if (self = [self initWithNibName:kNibName bundle:nil])
  {
    listOfIntervals = [sourceArray mutableCopy];
    currentValue    = [viewCurrentValue copy];
    title           = [viewTitle copy];
  }

  return self;
}

注意点:

  • このメソッドの名前は適切です。各引数には明確な名前があります。
  • 電話する必要はありません[NSBundle mainBundle]。ドキュメントに記載されているように、NSViewController はこれを自分で判断します。
  • 渡されたすべての引数がコピーされます。これには 2 つの重要な効果があります。
    • NSArrayNSString値オブジェクトです。つまり、コードは実際のオブジェクト自体ではなく、それらの値に関心があります。Cocoa は、これを可能な限り効率的に処理します。
    • -copyどちらも保持カウントが +1 のオブジェクトを-mutableCopt返すため、解放するまでどこにも移動しません。典型的なインスタンス変数に最適です。
于 2009-09-14T22:35:26.617 に答える