您的位置:首页 > 其它

多线程技术(三)

2016-05-20 20:00 162 查看
[Demo01_GCD_plist]

TRTableViewController.m

<span style="font-size:14px;">#import "TRTableViewController.h"
#import "TRDataManager.h"
#import "TRAlbum.h"
#import "TRTableViewCell.h"

@interface TRTableViewController ()

@property (nonatomic, strong) NSArray *albumsArray;
//存储下载好的图片的数据
@property (nonatomic, strong) NSMutableDictionary *imageMutableDic;

@end

@implementation TRTableViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.albumsArray = [TRDataManager getAllAlbums];
//初始化可变字典
self.imageMutableDic = [NSMutableDictionary dictionary];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.albumsArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TRTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"albumCell"];
// Configure the cell...
//singer/name
//数据源
TRAlbum *album = self.albumsArray[indexPath.row];
cell.textLabel.text = album.singer;
cell.detailTextLabel.text = album.name;
//赋值一个占位图片(两个lable不会最左边排列)
cell.imageView.image = [UIImage imageNamed:@"s0"];

//实现图片缓存的原理
//判断字典中有没有
NSData *readData = self.imageMutableDic[album.poster];
if (readData) {
//字典中有图片数据;显示
cell.imageView.image = [UIImage imageWithData:readData];
} else {
//字典中没有;判断沙盒中有没有
NSString *filePath = [self generateFilePath:album.poster];
NSData *dataFromFile = [NSData dataWithContentsOfFile:filePath];
if (dataFromFile) {
//沙盒中有图片数据;显示
cell.imageView.image = [UIImage imageWithData:dataFromFile];
} else {
//字典没有;沙盒没有;开始下载图片
[self downloadImageWithCell:cell withAlbum:album];
}
}

//下载图片
//    [self downloadImageWithCell:cell withAlbum:album];

return cell;
}

- (void)downloadImageWithCell:(TRTableViewCell *)cell withAlbum:(TRAlbum *)album {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSURL *imageURL = [NSURL URLWithString:album.poster];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
if (imageData) {
//存到字典中
self.imageMutableDic[album.poster] = imageData;
//存到沙盒文件中(文件所在的整个路径)
NSString *filePath = [self generateFilePath:album.poster];
[imageData writeToFile:filePath atomically:YES];
}
//返回主线程更新
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:imageData];

//            //刷新
//            [self.tableView reloadData];
});

});
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//    NSLog(@"dfafdsagagdg");
}

//返回已经拼接好的文件的路径
- (NSString *)generateFilePath:(NSString *)imageURLStr {
//找Caches路径
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
//获取url最后一部分:s2874587.jpg
//https://img1.doubanio.com/mpic/s2874587.jpg
NSString *imageName = [imageURLStr lastPathComponent];
return [cachesPath stringByAppendingPathComponent:imageName];
}
</span>


TRTableViewCell.m

<span style="font-size:14px;">- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
//当点击cell的时候,会自动触发这个方法;父类自动的重新设置cell的imageView的frame
//    [super setSelected:selected animated:animated];
//自定义cell选中的颜色
if (selected) {
//选中的颜色
[self setBackgroundColor:[UIColor colorWithRed:245.0/255 green:245.0/255 blue:245.0/255 alpha:1]];
} else {
//默认颜色
[self setBackgroundColor:[UIColor whiteColor]];
}

}</span>


TRAlbum.h

<span style="font-size:14px;">/** 歌曲名字 */
@property (nonatomic, copy) NSString *name;
/** 歌手名字 */
@property (nonatomic, copy) NSString *singer;
/** 专辑图片URL */
@property (nonatomic, copy) NSString *poster;</span>


TRDataManager.m

<span style="font-size:14px;">static NSArray *_albumsArray = nil;//只从文件中读一次
+ (NSArray *)getAllAlbums {
if (!_albumsArray) {
_albumsArray = [[self alloc] getAllAlbums];
}
return _albumsArray;
}

- (NSArray *)getAllAlbums {
//plist路径
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"albums.plist" ofType:nil];
//取plist数据
NSArray *plistArray = [NSArray arrayWithContentsOfFile:plistPath];
//for循环将字典转成TRAlbum
NSMutableArray *mutableArray = [NSMutableArray array];
for (NSDictionary *albumDic in plistArray) {
//NSDictionary -> Album
TRAlbum *album = [TRAlbum new];
[album setValuesForKeysWithDictionary:albumDic];
[mutableArray addObject:album];
}
return [mutableArray copy];
}
</span>


[Demo02_GCD_SDWebImage]

TRTableViewController.m

<span style="font-size:14px;">static void *imageViewFrameKey = &imageViewFrameKey;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TRTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"albumCell"];
// Configure the cell...
//singer/name
//数据源
TRAlbum *album = self.albumsArray[indexPath.row];
cell.textLabel.text = album.singer;
cell.detailTextLabel.text = album.name;
//赋值一个占位图片(两个lable不会最左边排列)
//    cell.imageView.image = [UIImage imageNamed:@"s0"];

//使用KVO方式监听cell的frame变化
[cell.imageView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:imageViewFrameKey];

//实现图片缓存的原理
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:album.poster] placeholderImage:[UIImage imageNamed:@"s0"]];

return cell;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == imageViewFrameKey) {
NSLog(@"====%@", change[@"new"]);

//此时监听到imageView的frame发生变化,改成自定义的frame值
UIImageView *imageView = (UIImageView *)object;
CGRect newRect = CGRectMake(20, 9, 60, 60);
if (!CGRectEqualToRect(imageView.frame, newRect)) {
imageView.frame = newRect;
}
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
</span>


[Demo03_Group]

<span style="font-size:14px;">// 1.创建一个group组对象
dispatch_group_t group = dispatch_group_create();
// 2.添加两个任务(5s; 8s);全局队列+异步执行
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
//子线程执行
NSLog(@"下载图片一开始");
[NSThread sleepForTimeInterval:5];
NSLog(@"下载图片一结束");
});
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"下载图片二开始");
[NSThread sleepForTimeInterval:8];
NSLog(@"下载图片二结束");
});
// 3.GCD中通知的方法,告诉两个任务完毕
dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
//子线程
NSLog(@"两个图片下载完毕,上传开始...");
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"开始更新新界面...");
});
});
</span>


[Demo04_Singleton]

<span style="font-size:14px;">//调用线程不安全单例方法
//需求:使用shared方法和使用alloc两种方法返回的对象都是同一个(更加严格单例方式)

//调用线程安全的严格的单例方法
//shared+alloc+copy
TRDataManager *firstDataManager = [TRDataManager sharedDataManagerBySafe];
TRDataManager *secondDataManager = [[TRDataManager alloc] init];
TRDataManager *thirdDataManager = [secondDataManager copy];
NSLog(@"first:%p; second:%p; third:%p", firstDataManager, secondDataManager, thirdDataManager);
</span>


DataManager.h

<span style="font-size:14px;">//返回单例对象,使用线程不安全方式
+ (instancetype)sharedDataManagerByUnsafe;

//返回单例对象,使用线程安全方式(GCD一次性任务)
+ (instancetype)sharedDataManagerBySafe;</span>


DataManager.m

<span style="font-size:14px;">static DataManager *_dataManagerByUnsafe = nil;
+ (instancetype)sharedDataManagerByUnsafe {
if (!_dataManagerByUnsafe) {
_dataManagerByUnsafe = [[DataManager alloc] init];
}
return _dataManagerByUnsafe;
}

////////////////////////////////////

static DataManager *_dataManagerBySafe = nil;
+ (instancetype)sharedDataManagerBySafe {
//1.创建一个静态的一次性任务对象
static dispatch_once_t onceToken;
//2.调用一次性任务方法
dispatch_once(&onceToken, ^{
//创建单例对象
_dataManagerBySafe = [[DataManager alloc] init];
});
//3.返回单例对象
return _dataManagerBySafe;
}
//重写alloc方法; 或者重写allocWithZone
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_dataManagerBySafe = [super allocWithZone:zone];
});
return _dataManagerBySafe;
}

//当copy当前类型对象时候,返回唯一的单例对象
- (id)copyWithZone:(NSZone *)zone {
return _dataManagerBySafe;
}

//////////////////////////////
//创建单例的方式三
static DataManager *_dataManagerByInit = nil;
+ (void)initialize {
if (self == [DataManager class]) {
//初始化操作;一定能保证只调用一次+线程安全的
_dataManagerByInit = [[DataManager alloc] init];
}
}
+ (instancetype)sharedDataManagerByInit {
return _dataManagerByInit;
}
</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: