0

私は画像256*256を並べて表示し、それらの並べて表示ファイルをディレクトリに書き戻すアプリを作成しています。更新がある場合は毎回URLを更新し、それらの画像を並べて表示してiphoneフォルダーに保存します。私は2つの主なことを心配しています:1)メモリ消費-サイズ200 KBの5つの画像のメモリ消費はたくさんありますか?2)5つの異なるURLを同時に画像と並べて表示する必要がある場合、アプリをどのくらいの速さで処理できますか?

1つのURLのディレクトリに並べて保存するコードを作成しましたが、5つのURLについても同じことをしたいと思います。このアプローチを採用することをお勧めしますか、それとも誰かが別のアプローチを採用している場合はどうでしょうか。

    - (void)viewDidLoad
    {
      [super viewDidLoad];

      NSString *URLString = @"http://www.abc.com/abc.html?event=123";   
      NSURL *url = [[NSURL alloc] initWithString:URLString];
      NSData * dataImage = [NSData dataWithContentsOfURL:url];

      NSString *directoryPath = [[NSBundle mainBundle] bundlePath];

      UIImage *big = [UIImage imageWithData:dataImage];
      [self saveTilesOfSize:(CGSize){256,256} forImage:big toDirectory:directoryPath          usingPrefix:@"image_124_"];  

       TileView *tv = [[TileView alloc] initWithFrame:(CGRect){{0,0}, (CGSize){5000,5000}}];
      [tv setTileTag:@"image_110_"];
      [tv setTileDirectory:directoryPath];

      [scrollView addSubview:tv];

      [scrollView setContentSize:(CGSize){5000,5000}];
    }


     - (void)saveTilesOfSize:(CGSize)size 
        forImage:(UIImage*)image 
        toDirectory:(NSString*)directoryPath 
        usingPrefix:(NSString*)prefix
     {
      CGFloat cols = [image size].width / size.width;
      CGFloat rows = [image size].height / size.height;

      int fullColumns = floorf(cols);
      int fullRows = floorf(rows);

      CGFloat remainderWidth = [image size].width - 
                      (fullColumns * size.width);
      CGFloat remainderHeight = [image size].height - 
                      (fullRows * size.height);


      if (cols > fullColumns) fullColumns++;
      if (rows > fullRows) fullRows++;

      CGImageRef fullImage = [image CGImage];

      for (int y = 0; y < fullRows; ++y) {
       for (int x = 0; x < fullColumns; ++x) {
       CGSize tileSize = size;
       if (x + 1 == fullColumns && remainderWidth > 0) {
       // Last column
       tileSize.width = remainderWidth;
       }

       if (y + 1 == fullRows && remainderHeight > 0) {
       // Last row
       tileSize.height = remainderHeight;
       }

       CGImageRef tileImage = CGImageCreateWithImageInRect(fullImage, 
                                    (CGRect){{x*size.width, y*size.height}, 
                                      tileSize});

        NSData *imageData = UIImagePNGRepresentation([UIImage imageWithCGImage:tileImage]);
       NSString *path = [NSString stringWithFormat:@"%@/%d.png", 
                    directoryPath, prefix];
  [imageData writeToFile:path atomically:NO];
 }
}    
}
4

1 に答える 1

1

私は同様の問題の解決策を実装しました(違いは、ディレクトリに保存していなかった、表示のみを目的としたものです)。異なるアプローチで。

私の問題では、I have 84 images of 250x250 dimension with size 8KB each(私はそれらを追加しscrollView、スクロールするとロードします。グーグルマップに少し似ていますが、よりスムーズです)。最初はあなたと同じアプローチを使っていましたが、パフォーマンスに問題がありました。そこで、非同期ローディングの概念を使用しました。接続されたデリゲートを使用してUIImageViewサブクラスを作成したため、UIImageViewサブクラスがその画像の読み込みを担当しました。また、読み込みは非同期であるため、パフォーマンスははるかに優れています。

あなたが尋ねたように

1)メモリ消費量-サイズ200 KBの5つの画像のメモリ消費量は多くなりますか?

Ans:5x200KB = 1MB〜1.2MB程度(表示するにはその量のメモリが必要になります。その量のメモリがある場合は心配する必要はありません)。私の場合は84x8KB = 672〜900KB(私が使用していたように)各imageviewのアクティビティインジケーターのようないくつかの追加のもの)。

2)5つの異なるURLを同時に画像と並べて表示する必要がある場合、アプリをどのくらいの速さで処理できますか?

Ans:viewDidLoad ...またはメインスレッドでロードしていると、パフォーマンスが問題になります(スレッドを使用しているかどうかが完全にわからないため、ブロッキングが発生する可能性があります)。

簡単な提案:

1. write an UIImageView subclass which has connection delegate methods.
2. have some method that you can call from outside to message this imageView to start loading.(give the url)
3. do proper deallocation of resources like responseData and connection object, once the downloading is complete.
4. when you move from this view to other view do proper deallocation and removal of all these imageviews.
5. use intruments to look for the allocations by this.

コード:

TileImageView.h

@interface TileImageView : UIImageView 
{
    NSURLConnection *serverConnection;
    BOOL isImageRequested;
    NSMutableData *responseData;

}
-(void) startImageDownloading:(NSString *)pRequestURL
-(void) deallocateResources;
-(BOOL) isImageRequested;
-(void)cancelConnectionRequest;

-(void) addActivityIndicator;
-(void) removeActivityIndicator;
@end

TileImageView.m

@implementation TileImageView


- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) 
    {
        // Initialization code.
        isImageRequested = NO;

    }
    return self;
}

-(BOOL) isImageRequested
{
    return isImageRequested;
}

-(void) startImageDownloading:(NSString *)pRequestURL
{


    if (!isImageRequested)
    {



        NSURL *pServerURL = [[NSURL alloc] initWithString:pRequestURL];
        if (pServerURL != nil) 
        {
            isImageRequested = YES;
            [self addActivityIndicator];
            [self setBackgroundColor:[UIColor lightGrayColor]];
            NSURLRequest *pServerRequest = [[NSURLRequest alloc]initWithURL:pServerURL];
            serverConnection = [[NSURLConnection alloc] initWithRequest:pServerRequest delegate:self];
            if(serverConnection)
            {
                responseData = [[NSMutableData alloc] init];
            }
            [pServerURL release];
            [pServerRequest release];
        }


    }

}

-(void) addActivityIndicator
{
    UIActivityIndicatorView *tempActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    CGFloat size = self.frame.size.width*0.12;
    [tempActivityIndicator setFrame:CGRectMake(0, 0, size, size)];
    [tempActivityIndicator setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)];
    [tempActivityIndicator setTag:1000];
    [tempActivityIndicator setHidesWhenStopped:YES];
    [tempActivityIndicator startAnimating];
    [self addSubview:tempActivityIndicator];
    [tempActivityIndicator release];
}

-(void) removeActivityIndicator
{
    UIActivityIndicatorView *tempActivityIndicator = (UIActivityIndicatorView *)[self viewWithTag:1000];
    if (tempActivityIndicator != nil)
    {
        [tempActivityIndicator stopAnimating];
        [tempActivityIndicator removeFromSuperview];
    }
}


-(void)cancelConnectionRequest
{
    if (isImageRequested && serverConnection != nil)
    {
        [serverConnection cancel];
        [self removeActivityIndicator];
        [self deallocateResources];
        isImageRequested = NO;
    }

}



// Name         :   connection: didReceiveAuthenticationChallenge:
// Description  :   NSURLConnectionDelegate method. Method that gets called when server sends an authentication challenge.
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

// Name         :   connection: didReceiveResponse:
// Description  :   NSURLConnectionDelegate method. Method that gets called when response for the launched URL is received..
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *) response 
{
    [responseData setLength:0]; 

}

// Name         :   connection: didReceiveData:
// Description  :   NSURLConnectionDelegate method. Method that gets called when data for the launched URL is received..
-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data 
{
    [responseData appendData:data];
}

// Name         :   connection: didFailWithError:
// Description  :   NSURLConnectionDelegate method. Method that gets called when an error for the launched URL is received..
-(void) connection:(NSURLConnection *) connection didFailWithError:(NSError *) error 
{
    NSLog(@"Error occured while loading image : %@",error);
    [self removeActivityIndicator];
    [self deallocateResources];


    UILabel *tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 150, 30)];
    [tempLabel setBackgroundColor:[UIColor clearColor]];
    [tempLabel setFont:[UIFont systemFontOfSize:11.0f]];
    [tempLabel setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)];
    [tempLabel setText:@"Image not available."];
    [self addSubview:tempLabel];
    [tempLabel release];

}

// Name         :   connectionDidFinishLoading
// Description  :   NSURLConnectionDelegate method. Method that gets called when connection loading gets finished.
-(void) connectionDidFinishLoading:(NSURLConnection *) connection 
{
    [self removeActivityIndicator];
    UIImage *tempImage = [[UIImage alloc] initWithData:responseData];
    self.image = tempImage;
    [tempImage release];
    [self deallocateResources];
}

-(void) deallocateResources
{

    if (serverConnection != nil) 
    {
        [serverConnection release];
        serverConnection = nil;
    }
    if (responseData != nil)
    {
        [responseData release];
        responseData = nil;
    }
}

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


@end

したがって、上記のコードを使用する場合は、TileImageViewのオブジェクトを追加し、メソッドを呼び出すだけ -(void) startImageDownloading:(NSString *)pRequestURLです。

Please use instruments to track allocations.

アップデート :

**How do I add TileImageView on scrollView ? :**

//このように、2D形状(12 x 7)グリッドで84枚の画像を追加します...画像が追加されたら、完全なグリッドサイズに従ってscrollViewのcontentSizeを設定します。

TileImageView *tileImageView  = [[TileImageView alloc]initWithFrame:<myFrameAsPerMyNeeds>];
[tileImageView setTag:<this is the identifier I use for recognizing the image>];
[myImageScrollView addSubView:tileImageView];
[tileImageView release];

..後でユーザースクロールや他の画像ビューが表示されるようになったときのコード。次のコードを使用します。

TileImageView * loadableImageView =(TileImageView *)[myImageScrollView viewWithTag:]; [loadableImageView startImageDownloading:];

drawRectカスタム描画を行う必要がないため、:で何もする必要はありません。

画像名の場合は、のタグプロパティを使用できますがimageView、文字列に似た別の名前が必要な場合はimageView、画像名に別のプロパティを入力して、画像ビューを追加するときに設定できます。didFinishLoadingデータを保存するために、のメソッドで画像がダウンロードされたらメソッドを呼び出すことができますTileImageView。ここで、その名前を使用できます。

SECODNアップデート

追加するTileImageView方法ScrollView

gridCount = 0;
rows = 7;
columns = 12;
totalGrids = rows*columns;
//*above : all are NSInteger type variable declared at class level

chunkWidth = 250;
chunkHeight = 250;
contentWidth = 0.0;
contentHeight = 0.0;
//*above : all are CGFloat type variable declared at class level
for (int i=0; i<rows; i++) 
{
    contentWidth = 0.0;
    for (int j=0 ; j<columns; j++)
    {

        gridCount++;
        CGRect frame = CGRectMake(contentWidth, contentHeight, chunkWidth, chunkHeight);
        [self addNewImageViewWithTag:gridCount frame:frame];
        contentWidth += chunkWidth;
    }
    contentHeight += chunkHeight;
}

[imageScrollView setContentSize:CGSizeMake(contentWidth, contentHeight)];
[imageScrollView setContentOffset:CGPointMake(0, 0)];
[imageScrollView setUserInteractionEnabled:YES];

そしてScrollViewDelegate方法で。

- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (isZoomed)
    {
        xOffset = scrollView.contentOffset.x;
        yOffset = scrollView.contentOffset.y;
        //*above : both are CGFloat type variable declared at class level

        visibleColumn = xOffset/chunkWidth+1;
        visibleRow = yOffset/chunkHeight+1;
        gridNumber = (visibleRow-1)*columns+visibleColumn;
        adjGrid1 = gridNumber+1;
        adjGrid2 = gridNumber+columns;
        adjGrid3 = adjGrid2+1;
        //*above : all are NSInteger type variable declared at class level
        if (gridNumber ==1)
        {
            [self createAndSendScrollRequest:gridNumber];
        }
        if (adjGrid1 > 0 && adjGrid1 <= totalGrids) 
        {
            [self createAndSendScrollRequest:adjGrid1];
        }
        if (adjGrid2 > 0 && adjGrid2 <= totalGrids) 
        {
            [self createAndSendScrollRequest:adjGrid2];
        }
        if (adjGrid3 > 0 && adjGrid3 <= totalGrids) 
        {
            [self createAndSendScrollRequest:adjGrid3];
        }
    }


}

そして、これがcreateAndSendScrollRequest実装方法です。

- (void) createAndSendScrollRequest:(NSInteger)chunkId
{

    TileImageView *loadingImageView = (TileImageView *)[imageScrollView viewWithTag:chunkId];
    if ([loadingImageView image]==nil) 
    {
        [loadingImageView startImageDownloading:<and here I pass url my url is based on tag so In reality I dont pass anything I just use it from the imageview's tag property>];
    }

}

ありがとう、

于 2011-05-13T03:32:02.517 に答える