处理异步数据加载后释放的表视图数据源数组

时间:2012-09-08 21:54:52

标签: objective-c ios uitableview asynchronous wsdl2objc

我是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

无法在[_newsList objectAtIndex:indexPath.row]中调用tableView:cellForRowAtIndexPath:。 有帮助吗?提前致谢

2 个答案:

答案 0 :(得分:1)

在主线程中调用updateNewView:方法newsListFromWebserveroperation:completedWithResponse:方法中创建的对象在该方法的最后一行中释放,因此被释放。解决问题的最简单方法是在_newsList内的operation:completedWithResponse: 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];
}

答案 1 :(得分:0)

你说你没有使用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];
}

希望这有帮助!