几个概念:
进程:“正在运行”应用程序(app)就是一个进程,它至少包含一个线程;
进程的作用:为应用程序开辟内存空间;
线程:CPU调度的最小单元;
线程的作用:执行app的代码;
进程和应用程序的关系:进程为应用程序开辟内存空间;
线程和应用程序的关系:线程执行应用程序的代码;
进程和线程之间的关系:进程是由线程组成的,一个进程中至少有一个线程;
iOS中开启线程
方法一:——C语言方式
pthread
步骤:
导入头文件:#import<pthread.h>
创建一个子线程:
pthread_create(<#pthread_t *restrict#>, <#const pthread_attr_t *restrict#>, <#void *(*)(void *)#>, <#void *restrict#>)
参数1:<#pthread_t *restrict#> 线程标识符的地址;
参数2:线程的属性;
参数3:函数指针(指向子进程中需要执行的函数);
参数4:传递给子进程的参数;
pthread_tmyPthread;
NSString
*str =
@"我是一个华丽的子线程";
NSString
*str =
@"我是一个华丽的子线程";
pthread_create(&myPthread,
NULL,
longTimeOperation, (__bridgevoid*)(str));
Source code:
#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
pthread_t myPthread;
NSString *str = @"我是一个华丽的子线程";
pthread_create(&myPthread, NULL, longTimeOperation, (__bridge void*)(str));
}
void *longTimeOperation(void * data){
for (int i = 0; i < 10000; i++) {
NSLog(@"%s : %d %@ %@",__func__,i,[NSThread currentThread],data);
}
return NULL;
}
方法二:——OC方式
利用 NSthread类
步骤:
实例化对象:
- (instancetype)initWithTarget:(id)target
selector:(SEL)selector object:(nullableid)argument
- (instancetype)initWithTarget:(id)target
selector:(SEL)selector object:(nullableid)argument
开启线程: [thread start];
实现线程方法:
进程属性:
(1)线程名称:(方便调试,主线程和子线程名称可以一样);
(2)线程内存大小 :(栈区)
iOS7之前,默认主1M,子512K;
现在,默认都是1M;
(3)线程优先级(慎用);
Source code:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *mythread = [[NSThread alloc] initWithTarget:self selector:@selector(longTimeOperation:) object:@"我是华丽的子进程"];
mythread.name = @"longTime";
[mythread start];
}
- (void)longTimeOperation:(NSString *)parameter {
for (int i = 0; i < 10000; i++) {
NSLog(@"%s : %d %@ %@",__func__,i,[NSThread currentThread],parameter);
if (i == 9999) {
NSLog(@"退出进程");
[NSThread exit];
}
}
}
除此以外:
还有两种开启进程的方法:
1、自动从当前线程分离出新线程NSThread的类方法
+ (void)detachNewThreadSelector:(SEL)selector
toTarget:(id)target withObject:(nullableid)argument;
toTarget:(id)target withObject:(nullableid)argument;
2、隐式的开启线程的方法(NSObject的分类)
- (void)performSelectorInBackground:(SEL)aSelector
withObject:(nullableid)arg
withObject:(nullableid)arg
常用方法:
名字/获得主线程/获得当前线程/阻塞线程/退出线程
//
不常用:栈区大小/优先级
1>获得当前线程
//
不常用:栈区大小/优先级
1>获得当前线程
+ (NSThread *)currentThread;
2>获得主线程
+ (NSThread *)mainThread;
3>睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4>设置线程的名字
- (void)setName:(NSString *)n;
- (void)setName:(NSString *)n;
- (NSString *)name;
线程的状态
当然除了以上两种方式,还有GCD和NSOperation,此文暂时不做分析;
线程同步技术:
可以解决多线程资源共享/竞争
利用锁技术来解决:
互斥锁:安静的等待
方式1、
NSLock
*lock = [[NSLockalloc]init];
//
加锁
加锁
[locklock];
//中间就是锁住的内容
//
解锁
[lockunlock];
方式二、
//唯一对象self
@synchronized(self){
}
原子锁:不停的敲门
原子锁 与互斥suo的区别:
一写多读,只为set方法加锁!不管读;
互斥锁则是读写都保护;
内存空间:
公共区域:每一个属性和对象都可以访问;
私人区域:需要加锁;
有限的公共区域:不能同时允许多个对象/属性访问;
为了解决“有限的公共区域:不能同时允许多个对象”的问题,信号量就诞生了!
信号量:互斥锁就是信号量为1的特殊情况;
进程间通信小案例:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
//NSLog(@"%s : %@",__func__,[NSThread currentThread]);
}
- (void)downLoadImage {
NSLog(@"%s : %@",__func__,[NSThread currentThread]);
NSString *urlStr = @"http://img5.duitang.com/uploads/item/201408/18/20140818224957_2tkUd.jpeg";
// urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
[self performSelectorOnMainThread:@selector(downLoadImageView:) withObject:image waitUntilDone:YES];
//NSLog(@"------");
}
- (void)downLoadImageView:(UIImage *)image {
//NSLog(@"%s : %@",__func__,[NSThread currentThread]);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
imageView.image = image;
[self.view addSubview:imageView];
}
@end
进程间通信案例总结:
1、iOS9网络适配
iOS9把所有之前的http请求全部改成了https请求。统一采用TLS 1.2 SSL。
解决方法分为两大类:
(1)服务器进行更更新。
据了解。这个应该是和服务器是什么系统有关。对应的解决方式也不同。应该是需要对症下药。
(2)移动端回退到之前相对来说不安全的http。
此时需要对Info.plist进行修改。
这里面又分为两大类:
指定某些请求使用之前的方式;
让所有的请求使用之前的方式。
指定某些请求使用之前的方式
Source code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>www.baidu.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
NSExceptionDomains:里面放的是允许使用http请求的sever字典。
www.baidu.com:允许使用http请求的sever的名字,里面放的是对这个sever的一切配置。
NSIncludesSubdomains:是否允许子域名。
NSTemporaryExceptionAllowsInsecureHTTPLoads:是否允许进行http请求。
让所有的请求使用之前的方式。
1 直接修改:info.plist
2 代码方式修改:open source Code info.plist文件:
Source code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
移动端而言,第一种方式相比第二种方式更加合理。第二种方式简单粗暴。如果偷懒,那自然是使用第二种方式。
参考:
2、百分号转义
URL:不能出现汉字/空格/特殊字符!
此时需要百分号转义
iOS9.0之前:
urlStr = [urlStr
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
iOS9.0之后:
urlStr = [urlStr
stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet
URLQueryAllowedCharacterSet]];