9

我有一个自定义UIView调用ActivityDetailView,我实例化然后添加到父视图控制器中的滚动视图。当这个自定义视图被分配时,每次额外的内存占用大约 1mb 并且 Instruments 显示内存永远不会被释放,即使视图和父视图控制器都dealloc调用了它们的方法。我收到内存警告,应用程序最终被杀死,所以我显然做错了什么。

更新了有关地图视图的信息是原因,但我需要修复

在自定义ActivityDetailViewnib 文件中,有一个以用户位置为中心的地图视图。当我从笔尖移除此地图视图以使其不在屏幕上绘制时,内存分配问题就消失了。但是,我显然需要地图视图。为什么地图视图超出范围时不会发布地图视图的数据?

视图显示时只有 1ActivityDetailView和 1ActivityDetailViewController活着。一旦我从堆栈中弹出视图,它们就不再存在了。即使通过 Instruments 显示对象被杀死,内存如何保持增长也没有意义。如果父视图被释放,为什么地图视图数据没有被释放?

我做错了什么或者我应该检查什么?

这是自定义视图:

@interface ActivityDetailView ()
{
    CLLocation *location;
    __weak id parentViewController;
    int scrollViewX;

    ImageUtility *imageUtility;
}
@end

@implementation ActivityDetailView

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        NSArray *xibViews = [[NSBundle mainBundle] loadNibNamed:@"ActivityDetailView" owner:nil options:nil];
        if ([xibViews count] < 1) return nil;
        ActivityDetailView * xibView = [xibViews objectAtIndex:0];
        [xibView setFrame:frame];
        self = xibView;
    }
    return self;
}

- (id)initWithLocation:(CLLocation *)loc parentController:(id)parent
{
    self = [self initWithFrame:CGRectMake(0, 0, 320, 1000)];
    if (self)
    {
        imageUtility = [ImageUtility sharedManager];

        location = loc;
        parentViewController = parent;
        scrollViewX = 0;

        [self centerMapForActivityLocation];
        [self addPhotoButtonWithImageNamed:@"addActivityPhoto.png" target:parentViewController selector:@selector(addPhotoToActivity:)];
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"ActivityDetailView was dealloced");
}

在父视图控制器中:

@interface ActivityDetailViewController ()
{
    ActivityDetailView *detailView;
}
@end

@implementation ActivityDetailViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Some code left out for clarity

    [self setupView];
}

- (void)didReceiveMemoryWarning
{
    NSLog(@"Purging image cache");
    [[ImageUtility sharedManager] purgeCache];
}

- (void)dealloc
{
    // These essentially do nothing to help the problem
    detailView.mapView = nil;
    [detailView removeFromSuperview];
    detailView = nil;
    self.scrollView = nil;

    NSLog(@"ActivityDetailViewController was dealloced");
}

- (void)setupView
{    
    // Add the activity detail view to the scroll view
    detailView = [[ActivityDetailView alloc] initWithLocation:self.activityLocation parentController:self];
    [self.scrollView addSubview:detailView];
    self.scrollView.contentSize = detailView.frame.size;

    // Setup the map view
    detailView.mapView.delegate = self;
    MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
    annotation.coordinate = self.activityLocation.coordinate;
    [detailView.mapView addAnnotation:annotation];
    if (self.activity.mapImageName) {
        detailView.mapView.scrollEnabled = YES;
        detailView.mapView.zoomEnabled = YES;
    } else {
        detailView.mapView.scrollEnabled = NO;
        detailView.mapView.zoomEnabled = NO;
    }

    // Add the weather area to the view
    dayView = [[DailyButtonView alloc] initWithFrame:CGRectMake(0, -17, 60, 70)];
    dayView.hidden = YES;
    [detailView.weatherView addSubview:dayView];
}

这是 Instruments 的一张图片,显示大部分内存来自 nib 加载

仪器截图

我目前没有要缓存的东西。该视图基本上是一个滚动视图,其中包含一个地图视图以及一些标签和几个表格视图。表格视图没有填充任何内容,并且除了滚动视图的背景图像之外,我没有在视图中加载任何图像,但是当视图加载时应该会被释放。

4

3 回答 3

22

事实证明,iOS 6 存在一个已知错误,并且MKMapView没有正确释放它的内存。不幸的是,除了试图强制地图视图清除它的缓存之外没有真正的解决方法,这对释放内存没有太大影响。

奇怪的是,即使应用程序收到内存警告,地图视图缓存仍然没有被正确清除。最终,应用程序变得不稳定并被操作系统杀死。

苹果最近的测试变得非常草率。MKMapView这是我遇到的第二个错误(另一个被mapViewDidFinishLoadingMap:提前调用),如果他们刚刚进行了一些性能和健全性测试,这两个错误都非常明显。

以下是一些可能有帮助的代码:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    // This is for a bug in MKMapView for iOS6
    [self purgeMapMemory];
}

// This is for a bug in MKMapView for iOS6
// Try to purge some of the memory being allocated by the map
- (void)purgeMapMemory
{
    // Switching map types causes cache purging, so switch to a different map type
    detailView.mapView.mapType = MKMapTypeStandard;
    [detailView.mapView removeFromSuperview];
    detailView.mapView = nil;
}

您可以做的另一件事是MKMapView在整个应用程序中使用一个实例,这应该有助于最大限度地减少每次显示视图时分配的内存量,因为地图视图已经被分配。

于 2013-05-07T15:46:11.903 回答
0

这并不是从 nib 文件创建自定义视图的最佳方式。我建议您做的是将您从 .nib 文件中获取的视图作为子视图添加到 self. 代码应该看起来像这样。

-(id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        NSArray *xibViews = [[NSBundle mainBundle] loadNibNamed:@"ActivityDetailView" owner:nil options:nil];
        if ([xibViews count] < 1) return nil;
        ActivityDetailView * xibView = [xibViews objectAtIndex:0];
        [xibView setFrame:frame];
        [self addSubview:xibView]; // This is where I have changed your code
    }
    return self;
}
于 2013-05-07T13:30:45.483 回答
0

您可能面临缓存问题。

如果您使用大量图像,则一个不错的选择是从 xib 中删除这些图像并使用代码添加它。或者,如果您使用加载图像 [UIImage imageNamed:@""]

但是使用类似的东西:

NSData* dataImg = [NSData dataWithContentsOfFile:@"yourfile.png"];
UIImage* img = [UIImage imageWithData:dataImg];

为了提供更好的帮助,我需要知道您如何开始您的表格以及其他功能。

于 2013-05-07T15:02:08.333 回答