消息发送到已释放的实例
我正在使用 TouchXML 来解析 iOS 中的元素。我使用 NSIncationOperation 从 Web 服务检索响应,然后解析并显示结果。一切正常,因为后台线程使用 [self PerformSelectorOnMainThread:@selector(displayLoginresult:) withObject:res waitUntilDone:NO]; 在主线程上显示结果,但随后出现错误:
2011-07-18 11:58:06.108 billsApp[873:7107] *** -[CFString release]: message sent to deallocated instance 0x5d809b0
要解析的代码元素是:
-(LoginResult *) tryLogin:(NSString *)userName withPassword:(NSString*)password{
NSURL *url = [UrlUtility TryLogin:userName passwordHash:password];
CXMLDocument *responseObj = [UrlUtility xmlDocWithUrl:url];
if(responseObj == [NSNull null])
return [NSNull null];
CXMLElement *eleUser = [responseObj nodeForXPath:@"//User" error:nil];
CXMLElement *eleResult = [responseObj nodeForXPath:@"//Result" error:nil];
LoginResultType resultType;
//NSLog(@"Result: ");
//NSLog(eleResult );
// NSLog([[eleResult stringValue] lowercaseString]);
if ([[[eleResult stringValue] lowercaseString ] isEqualToString: @"successful"]){
resultType = Successful;
} else {
resultType = InvalidUsernameOrPassword;
}
LoginResult *res = [[LoginResult alloc] init];
res.result = resultType;
for (CXMLElement *resultElement in [responseObj children] ) {
NSLog([NSString stringWithFormat:@"%@ %@", [resultElement name], [resultElement stringValue]]);
}
//todo: fix enum parsing =[LoginResult loginResultTypeStringToEnum: [eleResult stringValue]];
if(eleUser != nil) {
CXMLElement *eleClientID = [eleUser nodeForXPath:@"ClientID" error:nil];
CXMLElement *eleCompanyName = [eleUser nodeForXPath:@"CompanyName" error:nil];
CXMLElement *eleCompanyContact = [eleUser nodeForXPath:@"CompanyContact" error:nil];
CXMLElement *eleIsAgent = [eleUser nodeForXPath:@"IsAgent" error:nil];
CXMLElement *eleParentID = [eleUser nodeForXPath:@"ParentID" error:nil];
NSInteger *clientId = [[eleClientID stringValue] integerValue];
NSString *companyName = [eleCompanyName stringValue];
NSString *companyContact = [eleCompanyContact stringValue];
bool isAgent = [Utils stringToBool:[eleIsAgent stringValue]];
NSInteger *parentId = [[eleParentID stringValue] integerValue];
User *user = [[User alloc] initWithData:clientId companyName:companyName companyContact:companyContact isAgent:isAgent parentId:parentId];
res.user = user;
// release elements
// [eleClientID release];
// [eleCompanyName release];
// [eleCompanyContact release];
// [eleIsAgent release];
// [eleParentID release];
//release raw values
// [companyName release];
// [companyContact release];
}
// [eleResult release];
// [eleUser release];
return res;
}
我想说这是 TouchXML 的一个错误,但我发现这不太可能。有什么办法可以进一步追踪错误吗?
编辑: User 类的属性定义为:
@property (nonatomic, readwrite) NSInteger clientId;
@property (nonatomic, retain) NSString *companyName;
@property (nonatomic, retain) NSString *companyContact;
@property (nonatomic, readwrite) bool isAgent;
@property (nonatomic, readwrite) NSInteger parentId;
实例初始化为:
-(User*)initWithData:(NSInteger *)clientId companyName:(NSString *)company companyContact:(NSString*)contact isAgent:(bool)agent parentId:(NSInteger*)parentId {
//[self = super init];
self.clientId= clientId;
self.companyName= company;
self.companyContact= contact;
self.isAgent = agent;
self.parentId = parentId;
return self;
}
LoginResult 类为:
@interface LoginResult : NSObject {
LoginResultType result;
User *user;
NSString * const loginResultTypeArray[4];
}
@property (nonatomic, readwrite) LoginResultType result;
@property (nonatomic, retain) User *user;
I'm using TouchXML to parse an element in iOS. I retrieve a response from a web service using an NSInvocationOperation, then parse and display the results. Everything works fine as the background thread displays results on the main thread using [self performSelectorOnMainThread:@selector(displayLoginresult:) withObject:res waitUntilDone:NO];
but then I get an error:
2011-07-18 11:58:06.108 billsApp[873:7107] *** -[CFString release]: message sent to deallocated instance 0x5d809b0
The code to parse the element is:
-(LoginResult *) tryLogin:(NSString *)userName withPassword:(NSString*)password{
NSURL *url = [UrlUtility TryLogin:userName passwordHash:password];
CXMLDocument *responseObj = [UrlUtility xmlDocWithUrl:url];
if(responseObj == [NSNull null])
return [NSNull null];
CXMLElement *eleUser = [responseObj nodeForXPath:@"//User" error:nil];
CXMLElement *eleResult = [responseObj nodeForXPath:@"//Result" error:nil];
LoginResultType resultType;
//NSLog(@"Result: ");
//NSLog(eleResult );
// NSLog([[eleResult stringValue] lowercaseString]);
if ([[[eleResult stringValue] lowercaseString ] isEqualToString: @"successful"]){
resultType = Successful;
} else {
resultType = InvalidUsernameOrPassword;
}
LoginResult *res = [[LoginResult alloc] init];
res.result = resultType;
for (CXMLElement *resultElement in [responseObj children] ) {
NSLog([NSString stringWithFormat:@"%@ %@", [resultElement name], [resultElement stringValue]]);
}
//todo: fix enum parsing =[LoginResult loginResultTypeStringToEnum: [eleResult stringValue]];
if(eleUser != nil) {
CXMLElement *eleClientID = [eleUser nodeForXPath:@"ClientID" error:nil];
CXMLElement *eleCompanyName = [eleUser nodeForXPath:@"CompanyName" error:nil];
CXMLElement *eleCompanyContact = [eleUser nodeForXPath:@"CompanyContact" error:nil];
CXMLElement *eleIsAgent = [eleUser nodeForXPath:@"IsAgent" error:nil];
CXMLElement *eleParentID = [eleUser nodeForXPath:@"ParentID" error:nil];
NSInteger *clientId = [[eleClientID stringValue] integerValue];
NSString *companyName = [eleCompanyName stringValue];
NSString *companyContact = [eleCompanyContact stringValue];
bool isAgent = [Utils stringToBool:[eleIsAgent stringValue]];
NSInteger *parentId = [[eleParentID stringValue] integerValue];
User *user = [[User alloc] initWithData:clientId companyName:companyName companyContact:companyContact isAgent:isAgent parentId:parentId];
res.user = user;
// release elements
// [eleClientID release];
// [eleCompanyName release];
// [eleCompanyContact release];
// [eleIsAgent release];
// [eleParentID release];
//release raw values
// [companyName release];
// [companyContact release];
}
// [eleResult release];
// [eleUser release];
return res;
}
Part of me wants to say it's a bug with TouchXML, but I find that very unlikely. Is there any way to further track down the error?
EDIT: The definitions for the properties on the User class is:
@property (nonatomic, readwrite) NSInteger clientId;
@property (nonatomic, retain) NSString *companyName;
@property (nonatomic, retain) NSString *companyContact;
@property (nonatomic, readwrite) bool isAgent;
@property (nonatomic, readwrite) NSInteger parentId;
And the instance is initialized with:
-(User*)initWithData:(NSInteger *)clientId companyName:(NSString *)company companyContact:(NSString*)contact isAgent:(bool)agent parentId:(NSInteger*)parentId {
//[self = super init];
self.clientId= clientId;
self.companyName= company;
self.companyContact= contact;
self.isAgent = agent;
self.parentId = parentId;
return self;
}
And the LoginResult class is:
@interface LoginResult : NSObject {
LoginResultType result;
User *user;
NSString * const loginResultTypeArray[4];
}
@property (nonatomic, readwrite) LoginResultType result;
@property (nonatomic, retain) User *user;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试一下:您是否在
User
类中正确保留了companyName
和companyContatct
?编辑:
接下来我要检查的是
loginResultTypeArray
。字符串是如何分配给它的?我想这个建议对你来说也是微不足道的,但是用这么少的代码提出有用的建议真的很困难......你不能了解一下 which
CFString
实际上正在发布吗?如果它不是自动释放的对象,堆栈跟踪可能会指向发送release
消息的方法...这将非常有帮助...否则,我会尝试
NSLog
一些NSString
的地址,以便您可以将它们与错误日志中找到的地址进行比较(并且再次尝试找出释放后实际重用的字符串)。最后,另一种找出删除后使用哪个字符串的方法可能是使用方法调配,在调用调配的 < code>dealloc,对对象进行一些日志记录。这将产生大量日志信息,但是知道字符串的地址,您可以轻松找到所需的内容。 此处查找有关 swizzling 的信息。
Just a try: are you correctly retaining
companyName
andcompanyContatct
in yourUser
class?EDIT:
Next thing I would check is
loginResultTypeArray
. How are string assigned to it? I guess that this advice will also sound trivial to you, but it is really difficult to come up with useful suggestion with so little code...Can't you get some idea about which
CFString
is actually being released? If it is not an autoreleased object, possibly the stack trace could point at the method which is sending therelease
message... this would be very helpful...Otherwise, I would try and
NSLog
some of yourNSString
s addresses, so that you can compare them with the address you find in the error log (and, again, try and find out which string was actually reused after deallocation).Finally, another approach to find out which string is used after deletion could be using method swizzling to replace
NSString
'sdealloc
with a method of yours that, before calling the swizzleddealloc
, does some logging of the objec. This will produce much log info, but knowing the address of the string you could find easily what you need. Find here info about swizzling.追踪这件事简直就是一场噩梦。我有一个返回 NSString * 的方法,然后由另一个方法解析它以生成 XML 文档,然后由第二个方法释放。我实际上需要在第一种方法中自动释放它。
This was a nightmare to track down. I had a method which returned an
NSString *
, which was then parsed by another method to produce an XML document, then release by the second method. I actually needed to autorelease it in the first method.