委托和对象保留objective-c (iOS)
Posted
技术标签:
【中文标题】委托和对象保留objective-c (iOS)【英文标题】:Delegates and object retention objective-c (iOS) 【发布时间】:2013-07-14 04:58:55 【问题描述】:我在保留数组中的对象时遇到问题。我正在构建一个框架来与 Amazon Route 53 交互,并尽可能地关注 AWS ios 开发工具包的其余部分。我正在调用返回 XML 的 Web 服务。来自 Web 服务的响应由 NSXMLParser 委托编组到一个类中。委托切换到另一个委托来处理 XML 的嵌套部分。第二个委托类将嵌套部分解组为第二个类。第二类的对象放在第一类的一个数组中。当第二个委托被释放时,它正在释放对象(不是它们所在的数组,只是对象本身。当响应返回时,所有属性都被填充,但数组中的对象指向释放的对象(以及当然最终会调用一个已释放的对象)
这涉及到很多代码,所以我希望从委托中将对象分配给数组有明显的意义。我很确定我在整个过程中都在维护强引用,并且我认为如果将对象添加到数组中,则在释放数组之前它们不能/不会从中释放。
如果您有兴趣查看代码,请点击此处:
https://bitbucket.org/entr04y/aws-sdk-ios
应用程序位于示例子目录 (Route53_demo) 中,初始调用位于 ListHostedZonesViewController.m (viewWillAppear) 中。这会调用 src 目录中的 Route53 框架 - AmazonRoute53Client.m,它调用 Route53ListHostedZonesRequestMarshaller.m 作为解组响应的委托。第二个代表是 Route53HostedZoneUnmarshaller.m。
希望有人能指出我遗漏了什么......过去四天我一直在盯着它看,但我无法弄清楚我所做的与某些示例代码不同遵循相同模式的 AWS。
按照下面的要求,我将尝试添加代码的相关部分,因为这样做的方式似乎并不明显:
初始请求是从这样的视图控制器发出的:
Route53ListHostedZonesRequest *request = [[Route53ListHostedZonesRequest alloc] initWithMaxItems:100];
Route53ListHostedZonesResponse *listHostedZonesResponse = [[AmazonClientManager r53] listHostedZones:request];
然后在 AmazonRoute53Client.m(在我的框架中)中处理:
-(Route53ListHostedZonesResponse *)listHostedZones:(Route53ListHostedZonesRequest *)listHostedZonesRequest
AmazonServiceRequest *request = [Route53ListHostedZonesRequestMarshaller createRequest:listHostedZonesRequest];
return (Route53ListHostedZonesResponse *)[self invoke:request rawRequest:listHostedZonesRequest unmarshallerDelegate:[Route53ListHostedZonesResponseUnmarshaller class]];
响应被发送到 Route53ListHostedZonesResponseUnmarshaller.m 并解析为 Route53ListHostedZonesResponse 类的实例:
-(Route53ListHostedZonesResponse *)response
if (nil == response)
response = [[Route53ListHostedZonesResponse alloc] init];
return response;
当解析器命中包含托管区域的嵌套部分时,它被委派给另一个解组器 Route53HostedZoneUnmarshaller:
if ([elementName isEqualToString:@"HostedZone"])
[parser setDelegate:[[[Route53HostedZoneUnmarshaller alloc] initWithCaller:self withParentObject:self.response.hostedZones withSetter:@selector(addObject:)] autorelease]];
(hostedZones 被声明为 NSMutableArray 并且是 Route53HostedZonesResponse 类的非原子保留属性),它将 xml 中的项目放置到 XML 中包含的每个托管区域的 Route53HostedZone 实例中:
-(Route53HostedZone *)response
if (nil == response)
response = [[Route53HostedZone alloc] init];
return response;
在 xml 块的末尾,对象被返回给调用者,如下所示:
if ([elementName isEqualToString:@"HostedZone"])
if ( caller != nil)
[parser setDelegate:caller];
if (parentObject != nil && [parentObject respondsToSelector:parentSetter])
[parentObject performSelector:parentSetter withObject:self.response];
return;
在 xml 响应结束时,Route53ListHostedZonesResponse 对象填充如下:
if ([elementName isEqualToString:@"ListHostedZonesResponse"])
if (caller != nil)
[parser setDelegate:caller];
if (parentObject != nil && [parentObject respondsToSelector:parentSetter])
[parentObject performSelector:parentSetter withObject:self.response];
return;
此时,AWS 运行时库和 Route53 库已完成对响应的处理,解组器对象、Route53ListHostedZonesResponse 对象和所有 Route53HostedZone 对象都已释放。
回到视图控制器,当我尝试访问 listHostedZoneResponse 中的对象时,所有属性都可用,除了 hostsZones 数组中的对象现在是僵尸。我在 Route53HostedZoneUnmarshaller.m 中覆盖了 dealloc,如下所示:
-(void)dealloc
AMZLogDebug(@"deallocating zone object unmarshaller");
// [response release];
// [super dealloc];
这会阻止 unmarshaller 被释放并通过扩展 hostsZones 对象,此时代码可以工作(但当然会像筛子一样泄漏)我怎样才能将 Route53HostedZone 对象放入 hostsZones 数组以便保留它们?
【问题讨论】:
与其对正在发生的事情进行干巴巴的解释,为什么不放一些简化的代码来说明你在做什么呢?复制+粘贴嵌套的委托对象,删除除数组存储部分和委托处理代码之外的所有内容。这将真正提高获得解决方案的机会。 您是否对所有这些代码运行了静态分析器?你有收到任何警告吗?你修好了吗? 我同意@Can。由于您没有提供任何示例代码,因此我不了解您所面临问题的具体情况。对于没有处理过它的人来说,挖掘 AWS iOS 开发工具包是没有效率的。 @robmayoff:我得到的唯一警告是我已经覆盖了 dealloc。 @Can,希望这足以让您了解我在说什么。我最初希望是方法,而不是实现问题。 【参考方案1】:哇,这是一些令人费解的代码。我只是猜测问题可能出在这一行:
[parser setDelegate:
[[[Route53HostedZoneUnmarshaller alloc]
initWithCaller:self
withParentObject:self.response.hostedZones
withSetter:@selector(addObject:)]
autorelease]
];
我看不出parser
的类型是什么,但在Objective-C 中,通常不保留代表。所以整个Route53HostedZoneUnmarshaller
在使用的时候可能就是垃圾了。
尝试删除对autorelease
的调用并将委托对象存储在属性中,直到解析过程完成。
【讨论】:
解析器是一个 NSXMLParser。正如预期的那样,在解析过程完成之前,委托类将一直保留。问题是它创建的对象也在解析过程结束时被释放,即使它们被添加到最初在应用程序中创建的响应对象的 hostsZones 数组中。我认为将它们添加到数组中会保留它们。我想弄清楚的是如何将hostedZone对象添加到hostedZones数组中,以使它们以与原始响应对象中的所有其他对象相同的方式保留。NSMutableArray
中的对象被保留。当对象还在数组中时,它不可能变成僵尸。是什么让你觉得你得到了僵尸?您是否启用了 NSZombieEnabled 标志?您的对象可能会在它们添加到数组之前被释放。或者您正在访问数组中某个对象的属性并且该属性已被释放(数组无法控制这些属性)。
我在应用中启用了 NSZombie,我只是检查了一下,并没有在框架中打开它。一旦我这样做了,我发现被释放对象的原始问题不再是问题(实际上昨天已经修复),但是我输入的调试代码发现它现在是问题 以上是关于委托和对象保留objective-c (iOS)的主要内容,如果未能解决你的问题,请参考以下文章