2012-04-10 75 views
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 
+1

如果可以帮助,不要使用'[self release]'。 – Manuel 2012-04-10 12:56:31

+0

是的,'[自我释放]'是一个等待发生的崩溃。从父母释放。 – 2012-04-10 13:34:59

回答

2

自我保留非常偶尔是一种合适的模式。这很少见,但有时在某些类型的多线程代码中,确保在处理某些内容时不会消失很重要。这就是说,这不是其中之一。我很难想象一个你目前的方法会有所帮助的情况。如果有人创建了你的对象,然后再也不会调用startLoadingBook,那么它就会泄漏。如果有人拨打startLoadingBook,则无论如何都会保留您的对象,因为NSURLConnection会保留其委托直至完成。

这就是说,我相信你的问题很大程度上来自于你的对象模型是错误的。 GetBooksDownloadAndParseBook都不适合作为类。你可能的意思是BookManager(东西来容纳所有的书)和BookDownloadController(管理下载一本书的东西)。 BookManager应跟踪所有当前BookDownloadControllers(在NSSetNSArray伊娃)。每个BookDownloadController应该跟踪它的NSURLConnection(以ivar)。你不应该只是建立联系,让他们“自己挂”(即自我保留)。这感觉很方便,但它使代码很难处理。您无法控制您正在创建的连接数量。您无法取消连接。它变得非常迅速混乱。

+0

谢谢。我不想违反任何好的模式,所以我需要改变我的对象模型。你是对的。 – Voloda2 2012-04-10 15:00:26

0

问题是:为什么一个对象需要保留自己?您可能想要像单身人士一样实施您的课程。

+0

你可能要发表评论作为评论,而不是答案 – MrTJ 2012-04-10 13:28:11

1

不,这不是最佳做法。 保留/释放你的物体应该由物体的“所有者”完成。 对于您的特定示例,您的DownloadAndParseBook对象的所有者是执行alloc/init的对象。这应该是保留/释放您的DownloadAndParseBook实例。 这里的最佳实践是DownloadAndParseBook的alloc/init,保留由所有者完成,所有的下载/解析逻辑,然后向所有者发送回调,以完成所有操作(例如通过委托),在此时, ower向你的对象发送释放消息。

0

与其他响应者不同,我会说你的模式可能工作。另请参见Is calling [self release] allowed to control object lifetime?

有然而,在你的代码中的一些其他问题:

  • -(void) books我猜你想发送的startLoadingBook消息downloadAndParseBook,而不是self
  • 如果创建一个initWithAbook方法,它在您使用标准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 2012-04-10 15:08:23

+0

我就是这样。当我的连接委托被调用并且一切都已完成时,我调用[self release],否则你需要在你要求启动连接的地方保留一个指向你的其他类的指针,并且它很重。但即时通讯只是想你真的可以发送自己的代表谁可以释放它 – 2012-05-29 15:19:53

0

永远不要使用[self release]。唯一可能的例外是单例类/对象。方法releaseretain应该只由对象的所有者发送。这通常意味着无论哪个对象创建了该对象,也应该是释放该对象的对象。