2012-04-10 7 views
2

DownloadAndParseBook 클래스를 만들었습니다. 데이터 나 네트워크 오류가 발생하기 전에 자동 응답하지 않습니다.[self release], [self retain]을 사용하는 것이 좋은 방법입니까?

[자기 릴리즈], [자기 유지]를 사용했습니다. [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은 끝날 때까지 대리인을 보유하므로 개체가 보관됩니다.

그렇긴해도, 나는 당신의 문제가 당신의 객체 모델이 잘못되었다는 사실로부터 비롯된 것이라고 생각합니다. GetBooks 또는 DownloadAndParseBook도 클래스로 이해할 수 없습니다. 당신이 의미하는 바는 BookManager (모든 책을 수납 할 수있는 것)과 BookDownloadController (단행본의 다운로드를 관리하기위한 것)입니다. BookManager은 현재 BookDownloadControllers (NSSet 또는 NSArray ivar)을 모두 추적해야합니다. 각 BookDownloadControllerNSURLConnection (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 메소드는 객체 소유자 만 보내야합니다. 이는 대개 해당 객체를 생성 한 객체가 무엇이든지 그것을 릴리스하는 객체 여야 함을 의미합니다.