2012-04-10 11 views
2

私はDownloadAndParseBookクラスを作成しました。データやネットワークエラーが発生する前に自動返信されません。[self release]、[self retain]を使うのは良いアプローチですか?

[自己解放]、[自己保持]を使用しました。 [自己解放]、[自己保持]を使うのは良いアプローチですか? 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 
+1

あなたが助けることができるなら絶対に '[self release]'を使用しないでください。 – Manuel

+0

そうです、「[self release]」は起こるのを待っているクラッシュです。親からのリリース。 –

答えて

2

自己保持は非常にときどき適切なパターンです。まれですが、ある種のマルチスレッドコードでは、何かを処理する途中で消えないようにすることが重要です。つまり、これはその時代の一つではありません。あなたの現在のアプローチが役立つケースを想像するのが難しいです。誰かがあなたのオブジェクトを作成し、startLoadingBookを決して呼び出さない場合、それは漏れます。誰かがstartLoadingBookを呼び出すと、NSURLConnectionは終了するまでその代理人を保持するため、オブジェクトはとにかく保持されます。

あなたの問題の多くは、あなたのオブジェクトモデルが間違っているという事実から来ていると思います。 GetBooksDownloadAndParseBookもクラスとして意味がありません。あなたが意味するのは、BookManager(すべての書籍を保持するもの)とBookDownloadController(1つの書籍のダウンロードを管理するもの)です。 BookManagerは現在のBookDownloadControllersNSSetまたはNSArrayのivar)のすべてを追跡する必要があります。それぞれBookDownloadControllerは、そのNSURLConnection(ivar)を追跡する必要があります。接続を作成して「ハングアップ」する(自己保持する)だけではいけません。これは便利だが、コードを後で扱うのが非常に難しい。作成している接続の数を制御する方法はありません。接続をキャンセルする方法はありません。それは本当にすぐに混乱になります。

+0

ありがとう。良いパターンに違反したくないので、オブジェクトモデルを変更する必要があります。あなたが正しいです。 – Voloda2

0

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

+0

あなたはコメントではなく、コメントとして投稿することができます – MrTJ

1

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

0

他の応答者とは異なり、私はあなたのパターンが機能するかもしれないと言います。参照してくださいしかし、あなたのコード内の他のいくつかの問題がありますIs calling [self release] allowed to control object lifetime?

-(void) books

  • は、私はあなたがinitWithAbookメソッドを作成する場合self
  • downloadAndParseBookずにstartLoadingBookメッセージを送りたいと思いますが、それ標準のinitメソッドで本を起動すると呼び出されません。で[self retain]上記の現在のコードはbookID上記のコードで
  • が、私はここに「初期化」のパターンを使用していないだろうが、とのように、静的な機能のすべて呼び出し側がミスをすることはできません
  • を保存されません呼び出されることはありませんされますクラスの所有権。

コード:

- (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では、要求が処理されるまで生存している必要があるため、自動解放もできません。したがって、それが機能する唯一の方法は、上記のパターンです。

+0

私はdownvoterからのコメントを感謝したいと思います。 – MrTJ

+0

これはまさにこれです。私の接続デリゲートが呼び出され、すべてが完了したときに私は[self release]を呼び出します。そうしないと、接続を開始するように求めた場所から別のクラスにポインタを置く必要があります。しかし、私は実際にそれを解放することができた代議員に実際に自己を送ることができると考えている –

0

[self release]を絶対に使用しないでください。唯一可能な例外はシングルトンクラス/オブジェクトにあります。方法releaseretainは、オブジェクトの所有者によってのみ送信されるべきです。これは、通常、問題のオブジェクトを作成したオブジェクトがどれでもそれを解放するものであることを意味します。

関連する問題