2

DownloadAndParseBook クラスを作成しました。データまたはネットワーク エラーが発生する前に自動解放されることはありません。

【自己解放】、【自己保持】を使いました。【自己解放】、【自己保持】を利用するのは良いアプローチですか?DownloadAndParseBook には潜在的なバグが含まれていますか?

@implementation GetBooks

-(void) books
{ 
 for(int i =0; i<10; i++)
 {
   DownloadAndParseBook *downloadAndParseBook =
        [[[DownloadAndParseBook alloc] init]autorelease];
   [downloadAndParseBook startLoadingBook];
 }
}
@end


@implementation DownloadAndParseBook

- (id)initWithAbook:(int)bookID 
{
 if(self = [super init])
 { 
    [self retain];        
 }
 return self;
}

- (void)startLoadingBook
{
 [NSURLConnection connectionWithRequest:request delegate:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
  [self release];    
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
 [self saveResultToDatabase];
 [self release];
}


@end 
4

5 に答える 5

2

自己保持は、非常にまれな適切なパターンです。まれですが、特定の種類のマルチスレッド コードでは、何かを処理している最中に消えないようにすることが重要な場合があります。とはいえ、これはそれらの時代の1つではありません。あなたの現在のアプローチが役立つケースを想像するのに苦労しています. 誰かがあなたのオブジェクトを作成し、その後 を呼び出さない場合startLoadingBook、リークが発生します。誰かが を呼び出した場合、 は終了するまでデリゲートを保持するstartLoadingBookため、オブジェクトはとにかく保持されます。NSURLConnection

そうは言っても、あなたの問題の多くは、オブジェクト モデルが間違っているという事実から来ていると思います。クラスとしても意味がGetBooksありません。DownloadAndParseBookおそらくあなたが意味するのはBookManager、(すべての本を保持するもの)とBookDownloadController(単一の本のダウンロードを管理するもの)です。は、(またはivar 内の)BookManager現在のすべてを追跡する必要があります。それぞれがその(ivar で) を追跡する必要があります。単に接続を作成して、それらを「自分自身にぶら下がる」(つまり、自己保持) にするべきではありません。これは便利に思えますが、後でコードを処理するのが非常に難しくなります。作成している接続の数を制御する方法はありません。接続をキャンセルする方法はありません。それは本当にすぐに混乱します。BookDownloadControllersNSSetNSArrayBookDownloadControllerNSURLConnection

于 2012-04-10T14:27:38.953 に答える
1

いいえ、ベスト プラクティスではありません。オブジェクトの保持/解放は、オブジェクトの「所有者」が行う必要があります。特定の例では、DownloadAndParseBook オブジェクトの所有者は、alloc/init を実行するオブジェクトです。これは、 DownloadAndParseBook インスタンスを保持/解放するためのものです。ここでのベスト プラクティスは、DownloadAndParseBook の alloc/init であり、所有者によって行われたものを保持し、すべてのダウンロード/解析ロジックを保持し、すべての操作が完了したというコールバックを所有者に送信します (たとえば、デリゲートを介して)。 ower はオブジェクトにリリース メッセージを送信します。

于 2012-04-10T13:39:44.537 に答える
0

他のレスポンダーとは異なり、あなたのパターンはうまくいくかもしれません。[自己解放] を呼び出してオブジェクトの有効期間を制御することもできますか?も参照してください。

ただし、コードには他にもいくつかの問題があります。

  • -(void) books私はあなたがstartLoadingBookメッセージを送信したいdownloadAndParseBookと思っていると思います。self
  • メソッドを作成するinitWithAbookと、標準メソッドでブックを初期化しても呼び出されませんinit。上記の現在のコード[self retain]では、呼び出されることはありません
  • 上記のコードbookIDでは保存されません
  • ここでは「init」パターンは使用しませんが、静的関数内のすべてを使用するため、呼び出し元がクラスの所有権を間違えることはありません。

コード:

- (id) initWithId:(int)bookId {
  self = [super init];
  if (self) {
    // save bookId here
  }
  return self;
}

+ (void) startLoadingBookWithID:(int)bookId {
  DownloadAndParseBook* book = [[DownloadAndParseBook alloc] initWithId:bookId];
  [NSURLConnection connectionWithRequest:request delegate:book];
}

// release self when it finished the operation 
// and document well that its behaviour

よく考えれば、NSURLConnectionそれ自体もまったく同じように機能するはずですNSURLConnection。ただしconnectionWithRequest、リクエストが提供されるまで生きている必要があるため、それ自体を自動解放することもできません。したがって、それが機能する唯一の方法は、上記のパターンです

于 2012-04-10T13:53:18.197 に答える
0

絶対に使用しないでください[self release]。唯一の例外は、シングルトン クラス/オブジェクトです。メソッドreleaseretainオブジェクトの所有者のみが送信する必要があります。これは通常、問題のオブジェクトを作成したオブジェクトが、それを解放する必要があることを意味します。

于 2012-04-10T14:24:24.957 に答える
0

問題は、オブジェクトがそれ自体を保持する必要があるのはなぜですか? クラスをシングルトンのように実装したい場合があります。

于 2012-04-10T13:02:03.923 に答える