我有一个tableview来加载来自互联网的新闻。我试图将所有属性都设置为viewDidUnload。

- (void)viewDidUnload
{
    self.newsArray = nil;
    self.newsTableView = nil;
    self.indicatorView = nil;
//  self.iconDownLoader = nil;
    self.downloadArray = nil;

    [super viewDidUnload];
}


每次应用程序在viewDidUnload中崩溃。如果我评论self.iconDownLoader = nil ;,那就没问题了。那么有人可以告诉我为什么会这样吗?谢谢。

--------------------- NewsViewController.m --------------------------

//
//  NewsViewController.m
//
//  Created by on 18/01/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "NewsViewController.h"
#import "ASIHTTPRequest.h"
#import "SBJson.h"
#import "NewsModel.h"
#import "NewsDetailViewController.h"

#define kCustomRowCount 6
#define IconPlaceHolder @"Spinner"

@implementation NewsViewController

@synthesize appDelegate, newsTableViewCell, newsTableView, indicatorView;
@synthesize iconDownLoader, newsArray, downloadArray;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {

        // setup appDelegate
        self.appDelegate = (SydneyAppDelegate *)[[UIApplication sharedApplication] delegate];

        // initial arrays
        self.newsArray = [[NSMutableArray alloc] init];
        self.downloadArray = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    if(self.appDelegate.reachable) {
        [self getNews];
    }
    else
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No Connection" message:@"No Internet connection. Please try again later." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
    }
}

- (void)viewDidUnload
{
    self.newsArray = nil;
    self.newsTableView = nil;
    self.indicatorView = nil;
//  self.iconDownLoader = nil;
    self.downloadArray = nil;

    [super viewDidUnload];
}

#pragma mark - ASIHTTPRequest

- (void) getNews
{
    NSURL *url = [NSURL URLWithString:@"http://ferrarimaseratisydney.com/api/getPublicNews.html"];
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request setDelegate:self];
    [request startAsynchronous];
}

- (void) requestFinished:(ASIHTTPRequest *)request
{
    NSString *responseString = [request responseString];
    NSArray *json = [responseString JSONValue];

    for (id aNewsInJson in json)
    {
        NewsModel *aNews = [[NewsModel alloc] initWithJson:aNewsInJson];
        [self.newsArray addObject:aNews];
    }

    [self.indicatorView removeFromSuperview];

    [self.newsTableView reloadData];
}

- (void) requestFailed:(ASIHTTPRequest *)request
{
    NSError *error;
    error = [request error];
}

#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

    // Navigation logic may go here. Create and push another view controller.
    NewsDetailViewController *newsDetailViewController = [[NewsDetailViewController alloc] init];

    // transform news array
    newsDetailViewController.news = [self.newsArray objectAtIndex:indexPath.row];

    // Pass the selected object to the new view controller.
    [self.navigationController pushViewController:newsDetailViewController animated:YES];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [self.newsArray count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"NewsCellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"NewsTableViewCell" owner:self options:nil];
        cell = self.newsTableViewCell;
        self.newsTableViewCell = nil;
    }

    // read from newsModel
    NewsModel *news = [self.newsArray objectAtIndex:indexPath.row];

    UILabel *label;
    label = (UILabel *)[cell viewWithTag:10];
    label.text = [NSString stringWithString:news.title];
    label = nil;
    label = (UILabel *)[cell viewWithTag:11];
    label.text = [NSString stringWithString:news.description];
    UIImageView *imageView = (UIImageView *)[cell viewWithTag:12];
    imageView.image = news.image;

    if (news.image == nil)
    {
        imageView.image = [UIImage imageNamed:IconPlaceHolder];

        self.iconDownLoader = [[IconDownLoader alloc] init];
        self.iconDownLoader.url = news.imageUrl;
        self.iconDownLoader.delegate = self;
        self.iconDownLoader.indexPath = indexPath;
        if (self.appDelegate.ip4 == YES)
        {
            self.iconDownLoader.width = 300;
            self.iconDownLoader.height = 150;
        }
        else
        {
            self.iconDownLoader.width = 150;
            self.iconDownLoader.height = 75;
        }
        [self.downloadArray addObject:self.iconDownLoader];
        [self.iconDownLoader start];
    }
    return cell;
}

#pragma mark - IconDownLoaderDelegate

- (void)iconDownLoadFinsh:(NSData *)imageData row:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [self.newsTableView cellForRowAtIndexPath:indexPath];
    UIImageView *imageView = (UIImageView *)[cell viewWithTag:12];
    if (imageData != 0)
    {
        imageView.image = [UIImage imageWithData:imageData];
    }
    else
    {
        imageView.image = [UIImage imageNamed:@"icon57"];
    }
    NewsModel *newsModel = [self.newsArray objectAtIndex:indexPath.row];
    newsModel.image = [UIImage imageWithData:imageData];
}

@end


----------------------- IconDownLoader.m -------------------

//
//  IconDownLoader.m
//
//  Created by on 24/11/11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#import "IconDownLoader.h"
#import "ASIHTTPRequest.h"

@implementation IconDownLoader

@synthesize delegate = _delegate;
@synthesize url = _url;
@synthesize indexPath = _indexPath;
@synthesize width = _width;
@synthesize height = _height;
@synthesize request = _request;

- (void)start {

    NSString *originalString = @"width=%s&height=%s";
    NSString *newString = [NSString stringWithFormat:@"width=%d&height=%d&type=jpg", self.width, self.height];

    NSString *resizedURL = [self.url stringByReplacingOccurrencesOfString:originalString withString:newString];

    NSURL *url = [NSURL URLWithString:[resizedURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    _request = [ASIHTTPRequest requestWithURL:url];
    if (_indexPath) {
        _request.userInfo = [NSDictionary dictionaryWithObject:_indexPath forKey:@"indexPath"];
    }
    [_request setDelegate:self];
    [_request startAsynchronous];
}

- (void)requestFinished:(ASIHTTPRequest *)request {

    NSInteger statusCode = request.responseStatusCode;
    switch (statusCode) {
        case 401: // Not Authorized: either you need to provide authentication credentials, or the credentials provided aren't valid.
            break;

        case 200: {
            NSData *responseData = [request responseData];
            if (!responseData) {
                UIAlertView *alertView;
                alertView = [[UIAlertView alloc] initWithTitle:@"Oops" message:[NSString stringWithFormat:@"Download failed in row %d", _indexPath.row] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                return;
            }
            [_delegate iconDownLoadFinsh:responseData row:[request.userInfo objectForKey:@"indexPath"]];
        }
            break;

        default:{

        }
    }
}

- (void)dealloc {
    if (_request != nil) {
        [_request clearDelegatesAndCancel];
    }
}

@end

最佳答案

通常,在viewDidUnload中,您只应释放并归零所有对您拥有的nib对象的引用。

就是说,如果消耗大量内存,您也可以销毁viewDidUnload中的模型对象。您应该记住,viewDidUnloadviewDidLoad的对应物,因此一个好的经验法则是仅销毁您在viewDidUnload中创建的viewDidLoad中的那些对象。您还应该记住,释放视图控制器时不会调用viewDidUnload,仅当其视图被调用时才调用。

在您的情况下,我不会仅仅因为您在newsArray中创建它们而释放downloadArrayinit...。我只给他们发送removeAllObjects即可。

对于崩溃,每次单元需要图像时都创建一个新的共享图标下载器,这有点尴尬。如果确实需要共享下载器实例,则不应为每个单元都重新创建它。似乎您想将所有创建的下载程序保留在ivar数组中,因为每个下载程序都是一次性的,并且负责加载单个图像。

关于ios - viewDidUnload中的内存管理-我应该同时禁用数组和对象吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9187949/

10-11 14:44