How to handle tile images on the fly

I am writing an application that will display 256 * 256 images and write these files to a file. Each time I update my url if there are any updates and save these images and save them in iphone folder. Two main things bother me: 1) Memory consumption - will there be memory consumption for 5 images of 200 KB in size? 2) How fast can I process my application if I need to split 5 different URLs with images at the same time?

I wrote the code for breaking and storing in the directory at one URL and would like to do the same for 5 URLs. Is this approach recommended or if someone else has a different approach?

    - (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];
 }
}    
}
0
1

( , , .), .

I have 84 images of 250x250 dimension with size 8KB each ( scrollView , Google, ). , , . , . UIImageView connectiond, UIImageView . , .

1) - 5 200 ?

Ans: 5x200KB = 1 ~ 1,2 ( , , .).. 84x8KB = 672 ~ 900 ( , ).

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 ? :**

// 84 2D- (12 x 7)... 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:, custome.

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 tag property>];
    }

}

,

+1

All Articles