1

Instruments 报告了 2 个对象在每次调用 Soap Web 服务时泄漏,其中的代码由 SudzC 生成。

我已经缩小了一个简单的案例,使用代码调用免费的公共 Web 服务 ( http://www.webservicex.net/geoipservice.asmx?WSDL ) 并且没有身份验证。不幸的是,运行 SudzC 项目需要进行大量设置,但您可以通过将 WSDL URL 放入http://www.sudzc.com/并选择“iOS 中的 Objective-C”来查看生成的代码。

Leaked Object   #   Address Size    Responsible Library Responsible Frame
Malloc 1.00 KB,     0x5035400   1.00 KB Foundation-[NSCFString appendString:]
NSCFString,     0x4c3d390   32 Bytes    Foundation  -[NSPlaceholderMutableString init]

每个对象的调用堆栈是

3 Foundation -[NSCFString appendString:]
4 SoapDemo +[Soap createEnvelope:forNamespace:forParameters:withHeaders:] /Users/user1/Desktop/SRC/SoapDemo/SoapDemo/Soap/Soap.m:50
5 SoapDemo +[Soap createEnvelope:forNamespace:withParameters:withHeaders:] /Users/user1/Desktop/SRC/SoapDemo/SoapDemo/Soap/Soap.m:114
6 SoapDemo -[WSXGeoIPService GetGeoIP:action:IPAddress:] /Users/user1/Desktop/SRC/SoapDemo/SoapDemo/Generated/WSXGeoIPService.m:55
7 SoapDemo -[SoapDemoViewController callWebService] /Users/user1/Desktop/SRC/SoapDemo/SoapDemo/SoapDemoViewController.m:14
8 SoapDemo -[SoapDemoViewController press:] /Users/user1/Desktop/SRC/SoapDemo/SoapDemo/SoapDemoViewController.m:19

调用代码:

- (IBAction)press:(id)sender {
    NSLog(@"pressed");
    [self callWebService];
}

-(void)callWebService {
    WSXGeoIPService* service = [WSXGeoIPService service];
    [service GetGeoIP:self action:@selector(handleResponse:) IPAddress:@"209.85.147.103"];
}

-(void) handleResponse:(id)value{
    NSLog(@"%@", value);
}

根据 [Soap createEnvelope] 中的工具,Soap.m 中的违规行看起来很无害(标有注释)。

+ (NSString*) createEnvelope: (NSString*) method forNamespace: (NSString*) ns forParameters: (NSString*) params withHeaders: (NSDictionary*) headers
{
    NSMutableString* s = [NSMutableString string];
    [s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
    [s appendFormat: @"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns=\"%@\">", ns];
    if(headers != nil && headers.count > 0) {
        [s appendString: @"<soap:Header>"];
        for(id key in [headers allKeys]) {
            if([[headers objectForKey: key] isMemberOfClass: [SoapNil class]]) {
                [s appendFormat: @"<%@ xsi:nil=\"true\"/>", key];
            } else {
                [s appendString:[Soap serializeHeader:headers forKey:key]];
            }
        }
        [s appendString: @"</soap:Header>"];
    }
    [s appendString: @"<soap:Body>"];
    [s appendFormat: @"<%@>%@</%@>", method,[params stringByReplacingOccurrencesOfString:@"&" withString:@"&amp;"], method];
    [s appendString: @"</soap:Body>"];
    [s appendString: @"</soap:Envelope>"]; // *** this is reported as causing the leak ***
    return s;
}

我曾尝试修改该方法(通过组合 appendString 调用、添加一些虚拟日志记录等),但泄漏总是发生在此方法中。

我能想到几种可能:

  • Instruments 识别错误的代码中其他地方存在泄漏。
  • appendString 使用不正确。
  • Apple 的 NSMutableString appendString 方法存在泄漏。
  • 没有实际泄漏。

谁能推断出正在发生的事情(或如何找出答案)?

我正在使用 iOS SDK 4.3。

B计划是将项目转换为自动引用计数...

4

1 回答 1

1

对于那些不这样做的人,请按照我的更改来修复您的泄漏,因为它非常有效:

  1. 在 SoapRequest.h 中将变量声明替换id postDataNSString* postData
  2. 在 SoapRequest.h 中将其属性声明替换为@property (copy, nonatomic) NSString* postData(在这里,我另外将所有 NSString 属性声明更改为“复制”)
  3. 在 SoapRequest.m 中,方法 (SoapRequest*) create: (SoapHandler*) handler action: (SEL) action urlString: (NSString*) urlString soapAction: (NSString*) soapAction postData: (NSString*) postData deserializeTo: (id) deserializeTo 将行更改request.postData = [postData retain]request.postData = postData.

这 3 个步骤将解决您的问题。希望它也能在 SudzcC 框架中实现。

于 2012-10-04T09:54:15.660 回答