1、一个NSThread对象就代表一条线程
创建、启动线程
NSThread *thread = [[NSThread alloc] initWithTarget:self start];selector:@selector(run) object:nil];
[thread
// 线程一启动,就会告诉 CPU 准备就绪,可以随时接受 CPU 调度! CPU 调度当前线程之后,就会在线程thread中执行self的run方法
主线程相关用法
- (NSThread *)mainThread; // 获得主线程
- (BOOL)isMainThread; // 是否为主线程
- (BOOL)isMainThread; // 是否为主线程
2、获得当前线程
NSThread *current = [NSThread currentThread];
线程的调度优先级
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
- 调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
三、创建线程后自动启动线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
隐式创建并启动线程
[self performSelectorInBackground:@selector(run) withObject:nil];
上述2种创建线程方式的优缺点
优点:简单快捷
缺点:无法对线程进行更详细的设置
四、互斥锁使用格式
@synchronized(锁对象) { // 需要锁定的代码 }
注意:锁定1份代码只用1把锁,用多把锁是无效的
互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
互斥锁的使用前提:多条线程抢夺同一块资源
相关专业术语:线程同步
线程同步的意思是:多条线程在同一条线上执行(按顺序地执行任务)
互斥锁,就是使用了线程同步技术
五、OC在定义属性时有nonatomic和atomic两种选择
-
atomic:原子属性,为setter方法加锁(默认就是atomic)
nonatomic:非原子属性,不会为setter方法加锁
-
nonatomic和atomic对比
atomic:线程安全,需要消耗大量的资源
nonatomic:非线程安全,适合内存小的移动设备
-
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
六、既然多线程这么爽, 线程是不是越多越好呢?
<1> 开启线程需要消耗一定的内存(默认情况下,线程占用 512KB 的栈区空间);
<2> 会使应用程序增加很多代码!代码变多之后,程序复杂性就会提高!
<3> CPU 在多条线程之间来回切换!线程越多, CPU就越累!
建议: 在移动应用的开发中; 一般只开3~5条线程!
七、重点:为什么要使用桥接?你是怎么进行混合开发的?
{
桥接 (__bridge) :C 和 OC 之间传递数据的时候需要使用桥接! why?为什么呢?
1.内存管理:
在 OC 中,如果是在 ARC环境下开发,编译器在编译的时候会根据代码结构,自动为 OC 代码添加 retain/release/autorelease等. ----->自动内存管理(ARC)的原理!
但是, ARC只负责 OC 部分的内存管理!不会负责 C 语言部分代码的内存管理!
也就是说!即使是在 ARC 的开发环境中!如果使用的 C 语言代码出现了 retain/copy/new/create等字样呢!我们都需要手动为其添加 release 操作!否则会出现内存泄露!
在混合开发时(C 和 OC 代码混合),C 和 OC 之间传递数据需要使用 __bridge 桥接,目的就是为了告诉编译器如何管理内存
在 MRC中不需要使用桥接! 因为都需要手动进行内存管理!
2.数据类型转换:
Foundation 和 Core Foundation框架的数据类型可以互相转换的
Foundation : OC
Core Foundation : C语言
NSString *str = @"123"; // Foundation
CFStringRef str2 = (__bridge CFStringRef)str; // Core Foundation
NSString *str3 = (__bridge NSString *)str2;
CFArrayRef ---- NSArray
CFDictionaryRef ---- NSDictionary
CFNumberRef ---- NSNumber
Core Foundation中手动创建的数据类型,都需要手动释放
CGPathRef path = CGPathCreateMutable();
CGPathRetain(path);
CGPathRelease(path);
CGPathRelease(path);
3.桥接的添加:
利用 Xcode 提示自动添加! --简单/方便/快速
/**
凡是函数名中带有create\copy\new\retain等字眼, 都应该在不需要使用这个数据的时候进行release
GCD的数据类型在ARC环境下不需要再做release
CF(Core Foundation)的数据类型在ARC\MRC环境下都需要再做release
*/
}
八、iOS中多线程实现方案2.NSThread - 1基本使用
重点:1.三种创建线程! 2.常用方法!
{
1.NSThread: 一个 NSThread 就代表一个线程对象!
// OC语言 / 使用面向对象 / 需要手动管理线程生命周期(创建/销毁等)
2.三种多线程实现方案:
1> 先创建,后启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];
// 启动
[thread start];
2> 创建完自动启动
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:nil];
3> 隐式创建(自动启动)
[self performSelectorInBackground:@selector(download:) withObject:nil];
3.常用方法:
名字/获得主线程/获得当前线程/阻塞线程/退出线程
// 不常用: 栈区大小/优先级
1> 获得当前线程
+ (NSThread *)currentThread;
2> 获得主线程
+ (NSThread *)mainThread;
3> 睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4> 设置线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
}
九、重点:1.线程同步技术! 2.理解资源共享
{
当多条线程访问同一块资源的时候,就会出现数据错乱和数据安全的问题!
1.ATM机取钱; 卖票;
2.解决方案:互斥锁 @synchronized(锁对象self){ /*需要锁住的代码,越少越好!*/ } ------- 厕所加锁!
注意:锁定一份代码只用一把锁,用多把锁是无效的!
优点:能有效防止因多线程抢夺资源而引起的数据安全问题!
缺点:需要消耗大量的CPU资源!
结论:尽量少加锁!互斥锁的使用前提是多条线程抢夺同一块资源!
3.添加互斥锁技巧: [[NSUserDefaults standardUserDefaults] synchronize];
4.线程同步技术: ----- 互斥锁使用了线程同步技术!
多条线程在同一条线上按顺序执行任务!
5.线程安全:保证多条线程进行读写操作,都能够得到正确的结果!
用 '锁' 来实现线程安全!
}
十、为什么要在主线程更新UI?
因为UIKit 框架都不是线程安全的!为了得到更好的用户体验,UIKit框架牺牲了线程安全;
所以我们要在主线程更新UI;
十一、下载图片 更新 UI
/*------------------------- iOS中多线程实现方案2.NSThread - 4线程间通信 -------------------------*/
1.下载图片? 更新 UI?
{
1.后台线程(子线程)下载图片;
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
2.主线程更新 UI.
线程间通信常用方法:
// 最后一个参数:是否等待调用方法执行结束!
<1>[self performSelectorOnMainThread:@selector(setImageWithImage:) withObject:nil waitUntilDone:YES];
<2>[self performSelector:@selector(setImageWithImage:) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
}