耗时操作:1.网络请求 2.大量运算3.大文件相关4睡眠代码
1.不能在主线程中做耗时的操作
2.不能在子线程中修改页面的操作
三种开启线程的方式:
1.NSThread 没有线程队列的概念
- (IBAction)clicked:(UIButton *)sender {
//[NSThread sleepForTimeInterval:5];
NSLog(@"a");
[NSThread detachNewThreadWithBlock:^{
for (NSInteger i=0; i<5; i++) {
[NSThread sleepForTimeInterval:1];
NSLog(@"a%ld",i);
//回到主线程
[self performSelectorOnMainThread:@selector(updateUI:) withObject:@(i) waitUntilDone:NO ];
}
}];
NSLog(@"b");
//[NSThread detachNewThreadSelector:@selector(newThreadWithMethod:) toTarget:self withObject:s];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)updateUI:(NSNumber *)number{
int i = [number intValue];
UIView *v = [[UIView alloc]initWithFrame:CGRectMake(100, i*100, 80, 80)];
v.backgroundColor = [UIColor redColor];
[self.view addSubview:v];
}
2.GCD:GrandCentralDispatch 由C语言通过Block实现 效率高 有线程队列的概念
线程队列分为 串行队列 和并行队列
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//创建串行 线程对列
// NSLog(@"a");
// dispatch_queue_t myQueue = dispatch_queue_create("myQueue", 0);
// dispatch_async(myQueue, ^{
// for (NSInteger i = 0; i<3; i++) {
// [NSThread sleepForTimeInterval:5];
// NSLog(@"x-%ld",i);
// }
// });
// dispatch_async(myQueue, ^{
// for (NSInteger i = 0; i<3; i++) {
// [NSThread sleepForTimeInterval:5];
// NSLog(@"y-%ld",i);
// }
// });
// NSLog(@"b");
//获取系统提供的并行队列
dispatch_queue_t myQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i<3; i++) {
[NSThread sleepForTimeInterval:5];
NSLog(@"x-%ld",i);
//回到主线程修改页面
dispatch_async(dispatch_get_main_queue(), ^{
UIView *v = [[UIView alloc]initWithFrame:CGRectMake(100, i*100, 50, 50)];
v.backgroundColor = [UIColor redColor];
[self.view addSubview:v];
});
}
});
dispatch_async(myQueue, ^{
for (NSInteger i = 0; i<3; i++) {
[NSThread sleepForTimeInterval:5];
NSLog(@"y-%ld",i);
}
});
}
示例打地鼠
Mouse.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol MouseDelegate <NSObject>
-(void)successAction;
-(void)failAction;
@end
@interface Mouse : UIButton
@property(nonatomic,weak)id<MouseDelegate>delegate;
@end
Mouse.m
#import "Mouse.h"
@implementation Mouse
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if(self){
self.backgroundColor = [UIColor redColor];
[self addTarget:self action:@selector(clicked) forControlEvents:UIControlEventTouchUpInside];
[self setTitle:@"3" forState:UIControlStateNormal];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (NSInteger i = 0; i<3; i++) {
[NSThread sleepForTimeInterval:.5];
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
if(self.superview)//判断地鼠是否被删除了 如果删除了就不再修改title
{
int time = [[self titleForState:UIControlStateNormal] intValue] - 1;
[self setTitle:@(time).stringValue forState:UIControlStateNormal];
if(time == 0){
[self removeFromSuperview];
//失败次数+1
[self.delegate failAction];
}
}
});
}
});
// [NSThread detachNewThreadWithBlock:^{
//
// }];
}
return self;
}
-(void)clicked{
[self removeFromSuperview];
//成功次数+1
[self.delegate successAction];
ViewController.m
#import "ViewController.h"
#import "Mouse.h"
@interface ViewController ()<MouseDelegate>
@property (weak, nonatomic) IBOutlet UILabel *successLabel;
@property (weak, nonatomic) IBOutlet UILabel *failLabel;
@end
@implementation ViewController
-(void)successAction{
self.successLabel.text = @(self.successLabel.text.integerValue+1).stringValue;
}
-(void)failAction{
self.failLabel.text = @(self.failLabel.text.integerValue+1).stringValue;
}
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) , ^{
while (YES) {
[NSThread sleepForTimeInterval:0.8];
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
Mouse *m = [[Mouse alloc]initWithFrame:CGRectMake(arc4random()%355, arc4random()%876, 20, 20)];
m.delegate = self;
[self.view addSubview:m];
});
}
});
// [NSThread detachNewThreadWithBlock:^{
// }];
}
//-(void)addMouse{
// Mouse *m = [[Mouse alloc]initWithFrame:CGRectMake(arc4random()%355, arc4random()%876, 20, 20)];
// m.delegate = self;
// [self.view addSubview:m];
//}
屏幕效果
image.png
3.NSOperation 更灵活 可以设置并行数量 和 线程之间的关系
- 示例加载图片
TableViewController.m
#import "TableViewController.h"
@interface TableViewController ()
@property(nonatomic,strong)NSOperationQueue *myQueue;
@end
@implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.myQueue = [NSOperationQueue new];
self.myQueue.maxConcurrentOperationCount = 2;
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 100;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = @(indexPath.row).stringValue;
cell.imageView.image = nil;
//通过NSOperation实现图片异步加载
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
UIImage *image = [self downloadImage];
//通过GCD回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = image;
//刷新显示自身控件
//[iv setNeedsDispaly];
//重新显示子控件
[cell setNeedsLayout];
});
}];
[self.myQueue addOperation:op];
//通过GCD实现图片异步加载
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// UIImage *image = [self downloadImage];
// dispatch_async(dispatch_get_main_queue(), ^{
// cell.imageView.image = image;
// //刷新显示自身控件
// //[iv setNeedsDispaly];
// //重新显示子控件
// [cell setNeedsLayout];
// });
// });
return cell;
}
-(UIImage *)downloadImage{
[NSThread sleepForTimeInterval:.5];
return [UIImage imageNamed:@"timg.jpg"];
}
- 4.线程安全问题:当多条线程同时访问同一个数据的时候有可能会出现线程安全问题(示例卖票多线程通过同步代码块来解决的@synchronized (对象))
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic)int totalCount;
@property(nonatomic)int selledCount;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.totalCount = 100;
NSThread *t1 = [[NSThread alloc]initWithTarget:self selector:@selector(sellAction) object:nil];
t1.name = @"1号窗口";
[t1 start];
NSThread *t2 = [[NSThread alloc]initWithTarget:self selector:@selector(sellAction) object:nil];
t2.name = @"2号窗口";
[t2 start];
}
//
-(void)sellAction{
while (self.selledCount<=100) {
NSString *name = [NSThread currentThread].name;
@synchronized (self) {
NSLog(@"%@开始卖%d号票",name,self.selledCount+1);
[NSThread sleepForTimeInterval:.5];
self.selledCount++;
NSLog(@"%@卖掉了%d号票还剩%d张",name,self.selledCount,self.totalCount -self.selledCount);
}
}
}
网友评论