0

TouchXML を使用して iOS の要素を解析しています。NSInvocationOperation を使用して 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;
4

2 に答える 2

0

試してみてください:あなたは正しく保持companyNamecompanyContatctUserクラスにいますか?

編集:

次に確認するのはloginResultTypeArrayです。文字列はどのように割り当てられますか?このアドバイスもあなたにとって些細なことのように聞こえるかもしれませんが、非常に少ないコードで有用な提案を思い付くのは本当に難しいです...

どれ CFStringが実際にリリースされているのかわかりませんか?自動解放されたオブジェクトでない場合は、スタックトレースがreleaseメッセージを送信しているメソッドを指している可能性があります...これは非常に役立ちます...

それ以外の場合は、エラーログで見つけたアドレスと比較できるように、NSLogいくつかNSStringのアドレスを試してみます(また、割り当て解除後に実際に再利用された文字列を見つけてみてください)。

最後に、削除後に使用される文字列を見つける別のアプローチは、メソッドswizzlingを使用して、swizzledを呼び出す前に、オブジェクトのロギングを行う自分のメソッドNSStringに置き換えることです。これにより多くのログ情報が生成されますが、文字列のアドレスがわかれば、必要なものを簡単に見つけることができます。ここでスウィズリングに関する情報を見つけてください。deallocdealloc

于 2011-07-18T11:16:39.327 に答える
0

これは追跡するのに悪夢でした。を返すメソッドがありNSString *、それを別のメソッドで解析して XML ドキュメントを生成し、2 番目のメソッドで解放しました。最初の方法で実際に自動解放する必要がありました。

于 2011-07-19T09:35:05.073 に答える