私は同様の問題の解決策を実装しました(違いは、ディレクトリに保存していなかった、表示のみを目的としたものです)。異なるアプローチで。
私の問題では、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>];
}
}
ありがとう、