IOS開發之異步加載網絡圖片並緩存本地實現瀑布流(一)

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。緩存

[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片網絡

  1. </pre><pre name="code" class="objc">  異步

[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片函數

  1. </pre><pre name="code" class="objc">  url

[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片spa

  1. 在前面的一篇博客中,我寫了一個瀑布流照片牆的程序,因爲以前的程序加載的圖片是本地的,因此在這篇文章中我來補上有關異步加載網絡圖片的代碼,來實現以前程序的效果,但願你們批評指正呀!  .net

這個程序中大部分的代碼和以前的博客中貼出來的相同,不一樣的只是添加了圖片緩存機制,圖片異步下載線程函數,以及圖片點擊瀏覽的功能。線程

接下來看一下代碼實現部分:code


[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片orm

  1. #import "MyScrollView.h"  

  2.   

  3. #define COORDINATE_X_LEFT 5  

  4. #define COORDINATE_X_MIDDLE MY_WIDTH/3 + 5  

  5. #define COORDINATE_X_RIGHT MY_WIDTH/3 * 2 + 5  

  6. #define PAGESIZE 21  

  7.   

  8. @interface  MyScrollView ()  

  9.   

  10. @end   

  11.   

  12. @implementation MyScrollView  

  13.   

  14. @synthesize isOnce = _isOnce;  

  15. @synthesize imagesName = _imagesName;  

  16. @synthesize loadedImageDic = _loadedImageDic;  

  17. @synthesize leftColumHeight = _leftColumHeight;  

  18. @synthesize midColumHeight = _midColumHeight;  

  19. @synthesize rightColumHeight = _rightColumHeight;  

  20. @synthesize loadedImageArray = _loadedImageArray;  

  21. @synthesize imgTag = _imgTag;  

  22. @synthesize imgTagDic = _imgTagDic;  

  23. @synthesize imageLoad = _imageLoad;  

  24. @synthesize page = _page;  

  25. @synthesize fileUtil = _fileUtil;  

  26. @synthesize imageCache = _imageCache;  

  27. @synthesize photoArray = _photoArray;  

  28. //@synthesize aDelegaet;  

  29.   

  30. + (MyScrollView *)shareInstance{  

  31.     static MyScrollView *instance;  

  32.     static dispatch_once_t onceToken;  

  33.     dispatch_once(&onceToken, ^{  

  34.         instance = [[self alloc] initWithFrame:CGRectMake(00, MY_WIDTH, MY_HEIGHT)];  

  35.         });  

  36.       

  37.     return instance;  

  38. }  

  39.   

  40. /* 

  41.  初始化scrollView的委託以及背景顏色,不顯示它的水平,垂直顯示條 

  42.  */  

  43. - (id)initWithFrame:(CGRect)frame{  

  44.     self = [super initWithFrame:frame];  

  45.     if(self){  

  46.         self.delegate = self;  

  47.         self.backgroundColor = [UIColor blackColor];  

  48.         self.pagingEnabled = NO;  

  49.         self.showsHorizontalScrollIndicator = NO;  

  50.         self.showsVerticalScrollIndicator = NO;  

  51.           

  52.         self.isOnce = YES;  

  53.         self.loadedImageDic = [[NSMutableDictionary alloc] init];  

  54.         self.loadedImageArray = [[NSMutableArray alloc] init];  

  55.         self.imgTagDic = [[NSMutableDictionary alloc] init];  

  56.         self.photoArray = [[NSMutableArray alloc] init];  

  57.   

  58.         //初始化列的高度  

  59.         self.leftColumHeight = 3.0f;  

  60.         self.midColumHeight = 3.0f;  

  61.         self.rightColumHeight = 3.0f;  

  62.         self.imgTag = 10086;  

  63.         self.page = 1;  

  64.           

  65.         self.fileUtil = [FileUtil shareInstance];  

  66.         self.imageCache = [ImageCacher shareInstance];  

  67.           

  68.         _imageCache.myDelegate = self;  

  69.           

  70.         [self initWithPhotoBox];  

  71.     }  

  72.       

  73.     return self;  

  74. }  

  75.   

  76. /* 

  77.  將scrollView界面分爲大小相等的3個部分,每一個部分爲一個UIView, 並設置每個UIView的tag 

  78.  */  

  79. - (void)initWithPhotoBox{  

  80.     UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(00, MY_WIDTH/3self.frame.size.height)];  

  81.     UIView *middleView = [[UIView alloc] initWithFrame:CGRectMake(leftView.frame.origin.x + MY_WIDTH/30, MY_WIDTH/3,  

  82.                                                                   self.frame.size.height)];  

  83.     UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(middleView.frame.origin.x + MY_WIDTH/30, MY_WIDTH/3,  

  84.                                                                  self.frame.size.height)];  

  85.     //設置三個部分的tag  

  86.     leftView.tag = 100;  

  87.     middleView.tag = 101;  

  88.     rightView.tag = 102;  

  89.       

  90.     //設置背景顏色  

  91.     [leftView setBackgroundColor:[UIColor clearColor]];  

  92.     [middleView setBackgroundColor:[UIColor clearColor]];  

  93.     [rightView setBackgroundColor:[UIColor clearColor]];  

  94.       

  95.     [self addSubview:leftView];  

  96.     [self addSubview:middleView];  

  97.     [self addSubview:rightView];  

  98.       

  99.     self.imageLoad = [ImageLoader shareInstance];  

  100.     [_imageLoad loadImage:nil];  

  101.       

  102.     //第一次加載圖片  

  103.     for(int i = 0; i < PAGESIZE; i++){  

  104.         NSString *imageName = [_imageLoad.imagesArray objectAtIndex:i];  

  105.         [self imageStartLoading:imageName];  

  106.     }  

  107.       

  108.     //當前爲第一頁  

  109.     self.page = 1;  

  110. }  

  111.   

  112. /* 

  113.  * @brief 圖片加載通用函數 

  114.  * @parma imageName 圖片名 

  115.  */  

  116. - (void)imageStartLoading:(NSString *)imageName{  

  117.     NSURL *url = [NSURL URLWithString:imageName];  

  118.     if([_fileUtil hasCachedImage:url]){  

  119.         UIImageView *imageView = [[UIImageView alloc] init];  

  120.         NSString *path = [_fileUtil pathForUrl:url];  

  121.         imageView = [_imageLoad compressImage:MY_WIDTH/3 imageView:nil imageName:path flag:NO];  

  122.         [self addImage:imageView name:path];  

  123.         [self adjustContentSize:NO];  

  124.     }else{  

  125.         UIImageView *imageView = [[UIImageView alloc] init];  

  126.         NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:url, @"URL",  

  127.                              imageView, @"imageView", nil nil];  

  128.         [NSThread detachNewThreadSelector:@selector(cacheImage:) toTarget:[ImageCacher shareInstance] withObject:dic];  

  129.     }  

  130. }  

  131.   

  132.   

  133. /* 

  134.  *調整scrollview 

  135.  */  

  136. - (void)adjustContentSize:(BOOL)isEnd{  

  137.     UIView *leftView = [self viewWithTag:100];  

  138.     UIView *middleView = [self viewWithTag:101];  

  139.     UIView *rightView = [self viewWithTag:102];  

  140.       

  141.     if(_leftColumHeight >= _midColumHeight && _leftColumHeight >= _rightColumHeight){  

  142.         self.contentSize = leftView.frame.size;  

  143.     }else{  

  144.         if(_midColumHeight >= _rightColumHeight){  

  145.             self.contentSize = middleView.frame.size;  

  146.         }else{  

  147.             self.contentSize = rightView.frame.size;  

  148.         }  

  149.     }  

  150. }  

  151.   

  152. /* 

  153.  *獲得最短列的高度 

  154.  */  

  155. - (float)getTheShortColum{  

  156.     if(_leftColumHeight <= _midColumHeight && _leftColumHeight <= _rightColumHeight){  

  157.         return _leftColumHeight;  

  158.     }else{  

  159.         if(_midColumHeight <= _rightColumHeight){  

  160.             return _midColumHeight;  

  161.         }else{  

  162.             return _rightColumHeight;  

  163.         }  

  164.     }  

  165. }  

  166.   

  167. /* 

  168.  *添加一張圖片 

  169.  *規則:根據每一列的高度來決定,優先加載列高度最短的那列 

  170.  *從新設置圖片的x,y座標 

  171.  *imageView:圖片視圖 

  172.  *imageName:圖片名 

  173.  */  

  174. - (void)addImage:(UIImageView *)imageView name:(NSString *)imageName{  

  175.     //圖片是否加載  

  176.     if([self.loadedImageDic objectForKey:imageName]){  

  177.         return;  

  178.     }  

  179.       

  180.     //若圖片還未加載則保存  

  181.     [self.loadedImageDic setObject:imageView forKey:imageName];  

  182.     [self.loadedImageArray addObject:imageView];  

  183.     [_photoArray addObject:imageName];  

  184.       

  185.     [self imageTagWithAction:imageView name:imageName];  

  186.       

  187.     float width = imageView.frame.size.width;  

  188.     float height = imageView.frame.size.height;  

  189.       

  190.     //判斷哪一列的高度最低  

  191.     if(_leftColumHeight <= _midColumHeight && _leftColumHeight <= _rightColumHeight){  

  192.         UIView *leftView = [self viewWithTag:100];  

  193.         [leftView addSubview:imageView];  

  194.         //從新設置座標  

  195.         [imageView setFrame:CGRectMake(2, _leftColumHeight, width, height)];  

  196.         _leftColumHeight = _leftColumHeight + height + 3;  

  197.         [leftView setFrame:CGRectMake(00, MY_WIDTH/3, _leftColumHeight)];  

  198.     }else{  

  199.         if(_midColumHeight <= _rightColumHeight){  

  200.             UIView *middleView = [self viewWithTag:101];  

  201.             [middleView addSubview:imageView];  

  202.   

  203.             [imageView setFrame:CGRectMake(2, _midColumHeight, width, height)];  

  204.             _midColumHeight = _midColumHeight + height + 3;  

  205.             [middleView setFrame:CGRectMake(MY_WIDTH/30, MY_WIDTH/3, _midColumHeight)];  

  206.         }else{  

  207.             UIView *rightView = [self viewWithTag:102];  

  208.             [rightView addSubview:imageView];  

  209.   

  210.             [imageView setFrame:CGRectMake(2, _rightColumHeight, width, height)];  

  211.             _rightColumHeight = _rightColumHeight + height + 3;  

  212.             [rightView setFrame:CGRectMake(22 * MY_WIDTH/30, MY_WIDTH/3, _rightColumHeight)];  

  213.         }  

  214.     }  

  215. }  

  216.   

  217.   

  218. /* 

  219.  將圖片tag保存,以及爲UIImageView添加事件響應 

  220.  */  

  221. - (void)imageTagWithAction:(UIImageView *)imageView name:(NSString *)imageName{  

  222.     //將要顯示圖片的tag保存  

  223.     imageView.tag = self.imgTag;  

  224.     [self.imgTagDic setObject:imageName forKey:[NSString stringWithFormat:@"%ld", (long)imageView.tag]];  

  225.     self.imgTag++;  

  226.       

  227.     //圖片添加事件響應  

  228.     UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageClickWithTag:)];  

  229.     tapRecognizer.delegate = self;  

  230.     imageView.userInteractionEnabled = YES;  

  231.     [imageView addGestureRecognizer:tapRecognizer];  

  232.     [tapRecognizer release];  

  233. }  

  234.   

  235.   

  236. /* 

  237.      //若三列中最短列距離底部高度超過30像素,則請求加載新的圖片 

  238.  */  

  239. - (void)scrollViewDidScroll:(UIScrollView *)scrollView{  

  240.     //可視檢查  

  241.     //[self checkImageIsVisible];  

  242.     if((self.contentOffset.y + self.frame.size.height) - [self getTheShortColum] > 30){  

  243.         [self pullRefreshImages];  

  244.     }  

  245. }  

  246.   

  247.   

  248. /* 

  249.  上拉時加載新的圖片 

  250.  */  

  251. - (void)pullRefreshImages{  

  252.     int index = self.page *PAGESIZE;  

  253.     NSUInteger imgNum = [self.imageLoad.imagesArray count];  

  254.       

  255.     if(index >= imgNum){  

  256.         //圖片加載完畢  

  257.         [self adjustContentSize:YES];  

  258.     }else{  

  259.         if((imgNum - self.page*PAGESIZE) > PAGESIZE){  

  260.             for (int i = index; i < PAGESIZE; i++) {  

  261.                 NSString *imageName = [_imageLoad.imagesArray objectAtIndex:i];  

  262.                 [self imageStartLoading:imageName];  

  263.             }  

  264.         }else{  

  265.             for (int i = index; i < imgNum; i++) {  

  266.                 NSString *imageName = [_imageLoad.imagesArray objectAtIndex:i];  

  267.                 [self imageStartLoading:imageName];  

  268.             }  

  269.         }  

  270.         self.page++;  

  271.     }  

  272. }  

  273.   

  274. /* 

  275.  檢查圖片是否可見,若是不在可見視線內,則把圖片替換爲nil 

  276.  */  

  277. - (void)checkImageIsVisible{  

  278.     for (int i = 0; i < [_loadedImageArray count]; i++) {  

  279.         UIImageView *imgView = [_loadedImageArray objectAtIndex:i];  

  280.           

  281.         if((self.contentOffset.y - imgView.frame.origin.y) > imgView.frame.size.height ||  

  282.            imgView.frame.origin.y > (self.frame.size.height + self.contentOffset.y)){  

  283.             //不顯示圖片  

  284.             imgView.image = nil;  

  285.         }else{  

  286.             //從新根據tag值顯示圖片  

  287.             NSString *imageName = [self.imgTagDic objectForKey:[NSString stringWithFormat:@"%ld", (long)imgView.tag]];  

  288.             if((NSNull *)imageName == [NSNull null]){  

  289.                 return;  

  290.             }  

  291.               

  292.             UIImageView *view = [_imageLoad compressImage:MY_WIDTH/3 imageView:nil imageName:imageName flag:NO];  

  293.             imgView.image = view.image;  

  294.         }  

  295.     }  

  296. }  

  297.   

  298. //點擊圖片事件響應  

  299. - (void)imageClickWithTag:(UITapGestureRecognizer *)sender{  

  300.     UIImageView *view = (UIImageView *)sender.view;  

  301.     NSString *imageName = [self.imgTagDic objectForKey:[NSString stringWithFormat:@"%ld", (long)view.tag]];  

  302.       

  303.     PhotoViewController *photoView = [[PhotoViewController alloc] init];  

  304.     photoView.imageArray = _photoArray;  

  305.     photoView.imageName = imageName;  

  306.     UIWindow *window = [[UIApplication sharedApplication].delegate window];  

  307.     [window addSubview:photoView.view];  

  308. }  

  309.   

  310.   

  311. - (void)dealloc{  

  312.     [_imagesName release];  

  313.     [_imgTagDic release];  

  314.     [_loadedImageArray release];  

  315.     [_imageCache release];  

  316.     [_fileUtil release];  

  317.     [_imageLoad release];  

  318.     [_photoArray release];  

  319.     [super dealloc];  

  320. }  

  321.   

  322. @end  

當程序第一次加載或者下拉刷新時,就開始下載圖片,函數:imageStartLoading用於下載圖片,該函數爲每一次下載圖片都開啓一個線程,在ImageCacher類中有cacheImage函數,用於判斷該圖片是否已經存在本地,而且將圖片放入到視圖中去。

如下是ImageCacher類的代碼

[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. #import "ImageCacher.h"  

  2.   

  3. @implementation ImageCacher  

  4. @synthesize fileUtil = _fileUtil;  

  5. @synthesize imageLoader = _imageLoader;  

  6. @synthesize myDelegate = _myDelegate;  

  7.   

  8. + (ImageCacher *)shareInstance{  

  9.     static ImageCacher *instance;  

  10.     static dispatch_once_t onceToken;  

  11.     dispatch_once(&onceToken, ^{  

  12.         instance = [[self alloc] init];  

  13.     });  

  14.       

  15.     return instance;  

  16. }  

  17.   

  18. - (id)init{  

  19.     self = [super init];  

  20.     if(self){  

  21.         self.fileUtil = [FileUtil shareInstance];  

  22.         self.imageLoader = [ImageLoader shareInstance];  

  23.     }  

  24.     return self;  

  25. }  

  26.   

  27. - (void)cacheImage:(NSDictionary*)dic{  

  28.     NSURL *url = [dic objectForKey:@"URL"];  

  29.     NSFileManager *fileManage = [NSFileManager defaultManager];  

  30.     NSData *data = [NSData dataWithContentsOfURL:url];  

  31.       

  32.     NSString *fileName = [_fileUtil pathForUrl:url];  

  33.     if(data){  

  34.         [fileManage createFileAtPath:fileName contents:data attributes:nil];  

  35.     }  

  36.       

  37.     UIImageView *imageView = [dic objectForKey:@"imageView"];  

  38.     imageView.image = [UIImage imageWithData:data];  

  39.     imageView = [_imageLoader compressImage:MY_WIDTH/3 imageView:imageView imageName:nil flag:YES];  

  40.     [self.myDelegate addImage:imageView name:fileName];  

  41.     [self.myDelegate adjustContentSize:NO];  

  42. }  

  43.   

  44. - (void)dealloc{  

  45.     [super dealloc];  

  46. }  

  47.   

  48. @end  


因爲時間的關係,詳細的講解就留到下期來講吧!

[objc] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. #import "ImageCacher.h"  

  2.   

  3. @implementation ImageCacher  

  4. @synthesize fileUtil = _fileUtil;  

  5. @synthesize imageLoader = _imageLoader;  

  6. @synthesize myDelegate = _myDelegate;  

  7.   

  8. + (ImageCacher *)shareInstance{  

  9.     static ImageCacher *instance;  

  10.     static dispatch_once_t onceToken;  

  11.     dispatch_once(&onceToken, ^{  

  12.         instance = [[self alloc] init];  

  13.     });  

  14.       

  15.     return instance;  

  16. }  

  17.   

  18. - (id)init{  

  19.     self = [super init];  

  20.     if(self){  

  21.         self.fileUtil = [FileUtil shareInstance];  

  22.         self.imageLoader = [ImageLoader shareInstance];  

  23.     }  

  24.     return self;  

  25. }  

  26.   

  27. - (void)cacheImage:(NSDictionary*)dic{  

  28.     NSURL *url = [dic objectForKey:@"URL"];  

  29.     NSFileManager *fileManage = [NSFileManager defaultManager];  

  30.     NSData *data = [NSData dataWithContentsOfURL:url];  

  31.       

  32.     NSString *fileName = [_fileUtil pathForUrl:url];  

  33.     if(data){  

  34.         [fileManage createFileAtPath:fileName contents:data attributes:nil];  

  35.     }  

  36.       

  37.     UIImageView *imageView = [dic objectForKey:@"imageView"];  

  38.     imageView.image = [UIImage imageWithData:data];  

  39.     imageView = [_imageLoader compressImage:MY_WIDTH/3 imageView:imageView imageName:nil flag:YES];  

  40.     [self.myDelegate addImage:imageView name:fileName];  

  41.     [self.myDelegate adjustContentSize:NO];  

  42. }  

  43.   

  44. - (void)dealloc{  

  45.     [super dealloc];  

  46. }  

  47.   

  48. @end  

因爲時間的關係,詳細的講解就留到下期來講吧!

相關文章
相關標籤/搜索