【问题标题】:Table view data source array deallocated after handling asynchronous loading of data处理异步加载数据后释放的表视图数据源数组
【发布时间】:2012-09-09 18:22:27
【问题描述】:

我是 Objective-C 的新手,在异步调用后更新我的 UITableView 时遇到问题。 我有一个从NSMutableArray 填充的表格视图;我从 .net Web 服务的 JSON 响应中填充数组。我正在使用 wsdl2objc 从 Web 服务获取 JSON。

这是我的代码:

@interface NewsViewController : UITableViewController <ServiceSoapBindingResponseDelegate>

@property (nonatomic, strong) News *news;
@property (nonatomic, retain) NSMutableArray *newsList;

-(void) updateNewView:(NSMutableArray*) result;
-(void) loadNewsFromRemoteServer;

@end


-(void) viewDidLoad
{
    _newsList = [[NSMutableArray alloc] init];
    [self loadNewsFromRemoteServer];
    [super viewDidLoad];
}

-(void) loadNewsFromRemoteServer
{  
    NSString *customerID = @"xxx";
    NSString *uniqueID = @"xxx";    
    ServiceSoapBinding *bNews = [[ServiceSvc ServiceSoapBinding] retain];
    bNews.logXMLInOut = YES;
    ServiceSvc_GetNews *cRequest = [[ServiceSvc_GetNews new] autorelease];
    cRequest.id_ = customerID;
    cRequest.uniqueId = uniqueID;
    [bNews GetNewsAsyncUsingParameters:cRequest delegate:self];
}


-(void) operation:(ServiceSoapBindingOperation *)operation completedWithResponse:(ServiceSoapBindingResponse *)response
{
    NSArray *responseHeaders = response.headers;
    NSArray *responseBodyParts = response.bodyParts;
    NSMutableArray *newsListFromWebserver = [[NSMutableArray alloc] init];
    for(id header in responseHeaders) {
        // here do what you want with the headers, if there's anything of value in them
    }
    for(id bodyPart in responseBodyParts) {         
        if ([bodyPart isKindOfClass:[SOAPFault class]]) {
            // You can get the error like this:
            //NSLog(@"new list :: RESPONSE FROM SERVER :: %@",((SOAPFault *)bodyPart).simpleFaultString);
            continue;
        }
        //Get News List
        if([bodyPart isKindOfClass:[ServiceSvc_GetNewsResponse class]]) {
            ServiceSvc_GetNewsResponse *body = (ServiceSvc_GetNewsResponse*)bodyPart;
            NSString *nList = body.GetNewsResult;  //JSON FORMAT
            NSLog(@"new list :: RESPONSE FROM SERVER :: nList %@", nList);
            NSDictionary *resultsDictionary = [nList objectFromJSONString] ;
            for (NSDictionary * dataDict in resultsDictionary) {
                News *newNews = [[News alloc] init];
                _news = newNews;
                _news.newsTitle = [NSString stringWithFormat:[dataDict objectForKey:@"Title"]];
                _news.newsBody = [NSString stringWithFormat:[dataDict objectForKey:@"Body"]];
                _news.newsDate = [NSString stringWithFormat:[dataDict objectForKey:@"NewDate"]];
                [newsListFromWebserver addObject:_news];
               [_news release];
            }    
        }
    }   
    [self performSelectorOnMainThread:@selector(updateNewView:) withObject:newsListFromWebserver waitUntilDone:NO];
    [newsListFromWebserver release];
}

-(void) updateNewView:(NSMutableArray*) result
{
    _newsList = result;
    NSLog( @"new list - number of news :: %u", [_newsList count]);
    [self.tableView reloadData];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    static NSString *CellIdentifier = @"Cell";   
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }    
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    //Get the object from the array.
    News *cNews = [_newsList objectAtIndex:indexPath.row];
    cell.textLabel.text = cNews.newsDate;
    cell.detailTextLabel.text = cNews.newsTitle;
    cell.imageView.image = [UIImage imageNamed:@"bullet.png"];        
    return cell;
}

我的应用程序将此记录到控制台:

2012-09-08 22:36:45.463 xxx[45630:13a03] new list - number of news :: 1
2012-09-08 22:36:45.465 xxx[45630:13a03] *** -[__NSArrayM objectAtIndex:]: message sent to deallocated instance 0x79a3680

tableView:cellForRowAtIndexPath: 中调用[_newsList objectAtIndex:indexPath.row] 失败。 有什么帮助吗?提前致谢

【问题讨论】:

  • 您在使用 ARC 吗?你在使用自动合成的属性吗?
  • 我没有使用 ARC,是的,我在 m 中使用了 @synthesize。文件

标签: objective-c ios uitableview asynchronous wsdl2objc


【解决方案1】:

在主线程中调用updateNewView: 方法时,在operation:completedWithResponse: 方法中创建的newsListFromWebserver 对象在该方法的最后一行被释放并因此被释放。解决此问题的最简单方法是在 operation:completedWithResponse: 中为 _newsList ivar 赋值,然后在主线程中调用 updateNewView。请注意,在这种情况下,您可以从中删除 result 参数。

updateNewView 方法的第一行也有泄漏。

这是一个小提示:

-(void) operation:(ServiceSoapBindingOperation *)operation completedWithResponse:           (ServiceSoapBindingResponse *)response
{
    // your old parsing code here

    self.newsList = newsListFromWebserver;
    [newsListFromWebserver release];
    [self performSelectorOnMainThread:@selector(updateNewView) withObject:nil waitUntilDone:NO];
}

-(void) updateNewView
{
    NSLog( @"new list - number of news :: %u", [_newsList count]);
    [self.tableView reloadData];
}

【讨论】:

    【解决方案2】:

    你说你没有使用 ARC。你崩溃的原因是你为你的实例变量分配了一个自动释放的值而不是保留它:

    -(void) updateNewView:(NSMutableArray*) result
    {
        _newsList = result; // Should release the old and retain the new!
        NSLog( @"new list - number of news :: %u", [_newsList count]);
        [self.tableView reloadData];
    }
    

    我个人会更改您的整个程序以尽可能使用该属性,但至少您需要释放旧值并保留新值

    -(void) updateNewView:(NSMutableArray*) result
    {
        self.newsList = result;
        NSLog( @"new list - number of news :: %u", [_newsList count]);
        [self.tableView reloadData];
    }
    

    希望这会有所帮助!

    【讨论】:

    • 这样的改变肯定会有助于内存泄漏,但仍然不能保证传递给updateNewView的值没有被释放。
    • 啊,没看出不是回调。谢谢。
    • 很遗憾,我无法将程序更改为使用 ARC。我在这里尝试了两种解决方案..但没有..该值仍然被释放
    • @ellie, 你应该用self.newsList = newsListFromWebserver; [self performSelectorOnMainThread:@selector(updateNewView) withObject:nil waitUntilDone:NO]; 替换[self performSelectorOnMainThread:@selector(updateNewView:) withObject:newsListFromWebserver waitUntilDone:NO]; 你也应该用不接受任何参数的updateNewView 方法替换updateNewView:,请同时替换第一行旧的updateNewView: 方法。
    • 我已经更新了我的答案以使其更清楚,请检查。
    猜你喜欢
    • 2014-03-29
    • 1970-01-01
    • 2019-03-29
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    相关资源
    最近更新 更多