2

我有自定义 mapView(我将其命名为 JMMapView,它继承自 UIView),我在 UIScrollView 中创建了 UIImageView。它做一些基本的事情,如缩放、滚动、添加精确点等等。但主要问题是它加载了一个存储在 Documents 文件夹中的图像(图像在运行时下载并永久存储在文档文件夹中)并占用大量内存。例如,所有图像都是从 100kb 到 800kb,但只加载一个图像内存是从 20mb 到 40mb。我做错了什么?为什么需要这么多内存?我使用ARC,图像都是PNG,大小为2000x2000。

数据控制器.m

+(NSData*) getDataOfUrlString:(NSString*)urlString {
    NSString *fullLocalUrlString = [self formLocalDocumentsUrlWithPath:urlString];
    NSString *remoteUrl;
    NSData *data = [NSData dataWithContentsOfFile:fullLocalUrlString];
    if (!data) {
        NSString *remoteUrlString = [WSController formRequestURLWithMethod:urlString];
        remoteUrl = remoteUrlString;
        data = [NSData dataWithContentsOfURL:[NSURL URLWithString:remoteUrlString]];
        if (data) {
            [self createFoldersPathForFileWithFullUrlString:fullLocalUrlString];
            [data writeToFile:fullLocalUrlString atomically:YES];
        } else {
            WLog([NSString stringWithFormat:@"data was not even downloaded from url:%@", remoteUrlString]);
        }
    }

    if (!data) {
        DLog(@"loaded data:%@, from urlString:%@", data ? @"YES" : @"NO", fullLocalUrlString);
        DLog(@"Can't download from remote url:%@\n", remoteUrl);
    }
    return data;
}

MapPreviewViewController.m

//In background with @autoreleasepool
NSData* data = [DataController getDataOfUrlString:abstractUrl];
UIImage *image = nil;
if (data) {
     DLog(@"returning map image with path:%@", abstractUrl);
     image = [UIImage imageWithData:data];
}
 //On Main thread
if (image && !mapView) {
     mapView = [[JMMapView alloc] initWithImage:image fitSize:fitSize];
     [mapView setViewController:self];
     [self.view addSubview mapView];
}

JMMapView:UIView

#define KEY_BUTTON @"buttonKey"
#define KEY_COORDINATES @"coordinatesKey"
#define KEY_OBJECT @"jmObjectKey"

@interface JMMapView () {
    UIImageView *mapView;
    CGSize fitSize;
    NSArray *pinpoints;
    NSArray *directions;
    UIScrollView *scrollView;
    CGPoint pinchCenter;
    NSDictionary *currentPoint;

    NSDictionary *openPinpoint;
    UIViewController *activeViewController;

    FPPopoverController *popController;

}

@end

@implementation JMMapView

#pragma mark - initialization
-(id)initWithImage:(UIImage *)image fitSize:(CGSize)newSize {

    self = [self initWithFrame:CGRectMake(0, NAVIGATION_BAR_HEIGHT - 44, newSize.width, newSize.height)];
    if (self) {
        [self initMapViewWithImage:image fitSize:newSize];
    }
    return self;
}

-(void) initMapViewWithImage:(UIImage*)mapImage fitSize:(CGSize)newFitSize {

    mapView = [[UIImageView alloc] initWithImage:mapImage];
    [self finishInitWithFitSize:newFitSize];
}

-(void) finishInitWithFitSize:(CGSize)newFitSize {
    mapView.frame = [Utilities reframe:mapView.frame toFitSize:newFitSize];

    CGRect scrollFrame = CGRectMake(0, 0, newFitSize.width, newFitSize.height);
    scrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
    [scrollView setContentSize:newFitSize];
    [mapView setCenter:CGPointMake(scrollView.frame.size.width/2, scrollView.frame.size.height/2)];
    [mapView setUserInteractionEnabled:YES];

    [scrollView addSubview:mapView];
    [self addSubview:scrollView];


    fitSize = newFitSize;
    [self initZooming];

}
//gesture recognizer
...
//

#pragma mark - private methods
//pinch handling
..
//
//Add pinpoint
-(void) addPinpointToArray:(UIButton*)pin position:(JMMapPosition *)position pinpointType:(PINPOINT_TYPE)pinType object:(id)object{
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                          pin, KEY_BUTTON,
                          position, KEY_COORDINATES,
                          object, KEY_OBJECT,
                          nil];
    switch (pinType) {
        case PINPOINT_TYPE_CHILD_OBJECT:
        {
            if (!pinpoints) {
                pinpoints = [[NSArray alloc]  initWithObjects:dict, nil];
            } else {
                NSMutableArray *arrayM = [NSMutableArray arrayWithArray:pinpoints];
                [arrayM addObject:dict];
                pinpoints = [NSArray arrayWithArray:arrayM];
            }
            break;
        }

        case PINPOINT_TYPE_DIRECTION:
        {
            if (!directions) {
                directions = [[NSArray alloc]  initWithObjects:dict, nil];
            } else {
                NSMutableArray *arrayM = [NSMutableArray arrayWithArray:directions];
                [arrayM addObject:dict];
                directions = [NSArray arrayWithArray:arrayM];
            }
            break;
        }
        case PINPOINT_TYPE_OBJECT:
            currentPoint = dict;
            break;
        default:
            break;
    }
}


#pragma mark - public methods
-(void)setViewController:(UIViewController *)newController {
    if (activeViewController != newController) {
        activeViewController = newController;
    }
}



-(void)addPinpointWithObject:(id)object mapPosition:(JMMapPosition*)position pinpointType:(PINPOINT_TYPE)pinType
 {
    static UIImage *greenPin = nil;
    static UIImage *redPin = nil;
    static UIImage *directionPin = nil;
    if (greenPin == nil) {

        greenPin = [UIImage imageNamed:@"pin_green"];
        redPin = [UIImage imageNamed:@"pin"];
        //todo direction pin
        directionPin = [UIImage imageNamed:@"pin_direction"];
    }
    UIImage *image = nil;
    switch (pinType) {
        case PINPOINT_TYPE_CHILD_OBJECT:
            image = greenPin;
            break;

        case PINPOINT_TYPE_OBJECT:
            image = redPin;
            break;

        case PINPOINT_TYPE_DIRECTION:
            image = directionPin;
        default:
            break;
    }
    CGFloat width = image.size.width;
    CGFloat height = image.size.height;
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, width, height)];
     [self setButton:button positionToCoords:position];
    [button setBackgroundImage:image forState:UIControlStateNormal];

    [mapView addSubview:button];

    if (pinType == PINPOINT_TYPE_CHILD_OBJECT) {
        [button setTag:[pinpoints count]];
        [button addTarget:self action:@selector(pinpointPressed:) forControlEvents:UIControlEventTouchUpInside];
    } else if (pinType == PINPOINT_TYPE_DIRECTION) {
        [button setTag:[directions count]];
        [button addTarget:self action:@selector(directionPressed:) forControlEvents:UIControlEventTouchUpInside];

    }

    //add pinpoint to register
    [self addPinpointToArray:button position:position pinpointType:pinType object:object];
}

-(void) destroyAllMapView {
    //[self dismissPopover];
    [self setViewController:nil];
    for (NSDictionary *dict in pinpoints) {
        @autoreleasepool {
            UIButton *button = [dict objectForKey:KEY_BUTTON];
            [button removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents];
            //[button removeFromSuperview];

        }
    }
    [self setNilToEveryGlobalObject];
}
4

1 回答 1

2

图像压缩为 PNG 时可能为 100-800kb,但必须在内存中完全解压缩。

这意味着具有 Alpha 透明度 (RGBA) 的 2000x2000 图像将是 2000x2000x4 字节,或大约 15 兆字节。这就是为什么图像会占用这么多内存的原因。

您应该做的第一件事是确保图像没有 Alpha 通道,并且显示它们的视图已opaque设置YES为禁用任何透明度/混合。

您可能也应该使用基于图块的方法。Apple 有很好的示例代码,可以通过他们的PhotoScroller示例项目来演示这一点。

于 2012-12-19T15:41:49.787 回答