2

UIScrollViewでUIImageViewを作成したカスタムmapView(UIViewから継承されたJMMapViewと名付けました)があります。ズーム、スクロール、ピンポイントの追加などの基本的なことを行います。しかし、主な問題は、ドキュメント フォルダーに保存されている 1 つの画像を読み込み (画像は実行時にダウンロードされ、ドキュメント フォルダーに永続的に保存されます)、大量のメモリを消費することです。たとえば、すべての画像は 100kb から 800kb ですが、画像メモリを 1 つだけ読み込むと 20mb から 40mb になります。私が間違っていることは何ですか?なぜそんなに多くのメモリが必要なのですか?私はARCを使用しており、画像はすべて2000x2000のようなサイズのPNGです。

DataController.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 になる場合がありますが、メモリ内で完全に解凍する必要があります。

これは、アルファ透明度 (RGBA) を持つ 2000x2000 の画像が 2000x2000x4 バイト、つまり約 15 メガバイトになることを意味します。これが、画像が非常に多くのメモリを使用している理由です。

最初に行うべきことは、画像にアルファ チャンネルが含まれていないこと、および画像が表示されるビューが透過性/ブレンドを無効にするようにopaque設定されていることを確認することです。YES

おそらく、タイルベースのアプローチも使用する必要があります。Apple には、PhotoScrollerサンプル プロジェクトでこれを示す優れたサンプル コードがあります。

于 2012-12-19T15:41:49.787 に答える