**扩展:**苹果是单进程,沙盒资源会更安全,切换进程消耗资源会特别大,因此采用单进程体验更流畅安全
拓展:bash
内存五大分区markdown
堆区,栈区,未初始化常量区,初始化常量区,代码区多线程
临时变量存放在栈区并发
cpu 在单位时间片里快速在各个线程之间切换oop
#线程池的原理性能
经过"线程池大小小于核心线程池大小"判断线程池是否已满atom
若是未达到饱和 -> 建立线程执行任务spa
若是已达到饱和 -> 线程池判断工做队列已经满线程
1)未满 -> 将任务push进队列
2)满了
a. 且 maximumPoolSize > corePoolSize, 将建立新的线程来执行任务
b. 交给饱和策略去处理
a) Abort 策略:默认策略,新任务提交时直接抛出未检查的异常 RejectedExecutionException, 该异常可由调用者捕获
b)CallerRuns 策略:为调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者。不会在线程池的线程中执行新的任务,而是在调用 exector 的线程中运行新的任务。
c)Discard 策略:新提交的任务被抛弃
d)DiscardOldest 策略:队列的是“队头”的任务,而后尝试提交新的任务,(不适合工做队列为优先队列场景)
注意:start 不表明,立马开始跑
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument
- (void)start
- (void)cancel
+ (void)exit;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
sleep(unsigned int)
@property (readonly, getter=isExecuting) BOOL executing
@property (readonly, getter=isFinished) BOOL finished
@property (readonly, getter=isCancelled) BOOL cancelled
线程通信通常是指,多线程之间进行传值通信
**NSPort:**基于端的一些通信,端与端之间的通信
代码实现线程通信功能
PortViewController.m
#import "PortViewController.h" #import <objc/runtime.h> #import "KCPerson.h" @interface PortViewController ()<NSMachPortDelegate> @property (nonatomic, strong) NSPort *myPort; @property (nonatomic, strong) KCPerson *person; @end @implementation PortViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Port线程通信"; self.view.backgroundColor = [UIColor whiteColor]; //1. 建立主线程的port // 子线程经过此端口发送消息给主线程 self.myPort = [NSMachPort port]; //2. 设置port的代理回调对象 self.myPort.delegate = self; //3. 把port加入runloop,接收port消息 [[NSRunLoop currentRunLoop] addPort:self.myPort forMode:NSDefaultRunLoopMode]; self.person = [[KCPerson alloc] init]; [NSThread detachNewThreadSelector:@selector(personLaunchThreadWithPort:) toTarget:self.person withObject:self.myPort]; } #pragma mark - NSMachPortDelegate - (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"VC回调回来了 == %@",[NSThread currentThread]); } 复制代码
KCPerson.h
@interface KCPerson : NSObject
- (void)personLaunchThreadWithPort:(NSPort *)port;
@end
复制代码
KCPerson.m
#import "KCPerson.h" @interface KCPerson()<NSMachPortDelegate> @property (nonatomic, strong) NSPort *vcPort; @property (nonatomic, strong) NSPort *myPort; @end @implementation KCPerson - (void)personLaunchThreadWithPort:(NSPort *)port{ NSLog(@"VC 响应了Person里面"); @autoreleasepool { //1. 保存主线程传入的port self.vcPort = port; //2. 设置子线程名字 [[NSThread currentThread] setName:@"KCPersonThread"]; //3. 开启runloop [[NSRunLoop currentRunLoop] run]; //4. 建立本身port self.myPort = [NSMachPort port]; //5. 设置port的代理回调对象 self.myPort.delegate = self; //6. 完成向主线程port发送消息 [self sendPortMessage]; } } /** * 完成向主线程发送port消息 */ - (void)sendPortMessage { NSData *data1 = [@"ty" dataUsingEncoding:NSUTF8StringEncoding]; NSMutableArray *array =[[NSMutableArray alloc]initWithArray:@[data1,self.myPort]]; // 发送消息到VC的主线程 // 第一个参数:发送时间。 // msgid 消息标识。 // components,发送消息附带参数。 // reserved:为头部预留的字节数 [self.vcPort sendBeforeDate:[NSDate date] msgid:10086 components:array from:self.myPort reserved:0]; } 复制代码
打印结果:
以上代码主要是完成了这样一个流程 :
PortViewController -> KCPerson -> PortViewController
这样就完成了基于端与端之间的通信,而且是指主线程和子线程之间完成的。
而后咱们看到NSPort 的代理 NSMachPortDelegate 方法
- (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"VC回调回来了 == %@",[NSThread currentThread]); } 复制代码
回调有个参数 NSPortMessage,查看一下里面都有哪些参数
PortViewController.m
#pragma mark - NSMachPortDelegate - (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"VC回调回来了 == %@",[NSThread currentThread]); [self getAllProperties:message]; } - (void)getAllProperties:(id)somebody{ u_int count = 0; objc_property_t *properties = class_copyPropertyList([somebody class], &count); for (int i = 0; i < count; i++) { const char *propertyName = property_getName(properties[i]); NSLog(@"%@",[NSString stringWithUTF8String:propertyName]); } } 复制代码
打印结果:
知道了带有哪些参数,那咱们就读取打印一下以前回传时的数据
- (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"VC回调回来了 == %@",[NSThread currentThread]); NSLog(@"从person 传过来一些信息:");\ NSLog(@"receivePort == %@",[message valueForKey:@"receivePort"]); NSLog(@"sendPort == %@",[message valueForKey:@"sendPort"]); NSLog(@"msgid == %@",[message valueForKey:@"msgid"]); NSLog(@"components == %@",[message valueForKey:@"components"]); 复制代码
打印结果:
刚才完成的是 PortViewController 跟 KCPerson 通信,而后 KCPerson 使用 NSPort 又向 PortViewController 发消息的流程,
接下来在添加一个流程,刚才 PortViewController 有收到 KCPerson 向它发送的消息,那么如今 PortViewController 接受到消息以后,再给 KCPerson 发一个消息
代码实现:
PortViewController.m
#import "PortViewController.h" #import <objc/runtime.h> #import "KCPerson.h" @interface PortViewController ()<NSMachPortDelegate> @property (nonatomic, strong) NSPort *myPort; @property (nonatomic, strong) KCPerson *person; @end @implementation PortViewController - (void)viewDidLoad { [super viewDidLoad]; self.title = @"Port线程通信"; self.view.backgroundColor = [UIColor whiteColor]; NSLog(@"PortViewController 新建子线程,去调用 KCPerson 主线程的方法\n"); //1. 建立主线程的port // 子线程经过此端口发送消息给主线程 self.myPort = [NSMachPort port]; //2. 设置port的代理回调对象 self.myPort.delegate = self; //3. 把port加入runloop,接收port消息 [[NSRunLoop currentRunLoop] addPort:self.myPort forMode:NSDefaultRunLoopMode]; self.person = [[KCPerson alloc] init]; [NSThread detachNewThreadSelector:@selector(personLaunchThreadWithPort:) toTarget:self.person withObject:self.myPort]; } #pragma mark - NSMachPortDelegate - (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"收到 KCPerson 发的消息后, PortViewController 又给 KCPerson 发送消息\n"); NSData *data2 = [@"Janice" dataUsingEncoding:NSUTF8StringEncoding]; //此 sendPort 是在 KCPerson 里新建的那个 port,因此在使用它发送消息时,须要加入到 NSRunLoop 中 NSPort *sendPort = [message valueForKey:@"sendPort"]; NSMutableArray *array = [[NSMutableArray alloc] initWithArray:@[data2, self.myPort]]; [[NSRunLoop currentRunLoop] addPort:sendPort forMode:NSDefaultRunLoopMode]; // 发送消息KCPerson的主线程 // 第一个参数:发送时间。 // msgid 消息标识。 // components,发送消息附带参数。 // reserved:为头部预留的字节数 BOOL ruselt = [sendPort sendBeforeDate:[NSDate date] msgid:10000 components:array from:self.myPort reserved:0]; } 复制代码
KCPerson.h
#import <Foundation/Foundation.h> @interface KCPerson : NSObject - (void)personLaunchThreadWithPort:(NSPort *)port; @end 复制代码
KCPerson.m
#import "KCPerson.h" @interface KCPerson()<NSMachPortDelegate> @property (nonatomic, strong) NSPort *vcPort; @property (nonatomic, strong) NSPort *myPort; @end @implementation KCPerson - (void)personLaunchThreadWithPort:(NSPort *)port{ NSLog(@"KCPerson 里的方法在 PortViewController 里经过子线程被调用了\n"); @autoreleasepool { //1. 保存主线程传入的port self.vcPort = port; //2. 设置子线程名字 [[NSThread currentThread] setName:@"KCPersonThread"]; //3. 开启runloop [[NSRunLoop currentRunLoop] run]; //4. 建立本身port self.myPort = [NSMachPort port]; //5. 设置port的代理回调对象 self.myPort.delegate = self; //6. 完成向主线程port发送消息 [self sendPortMessage]; } } /** * 完成向主线程发送port消息 */ - (void)sendPortMessage { NSLog(@"KCPerson 给 PortViewController 发送消息\n"); NSData *data1 = [@"ty" dataUsingEncoding:NSUTF8StringEncoding]; NSData *data2 = [@"Janice" dataUsingEncoding:NSUTF8StringEncoding]; NSMutableArray *array =[[NSMutableArray alloc]initWithArray:@[data1,self.myPort]]; // 发送消息到VC的主线程 // 第一个参数:发送时间。 // msgid 消息标识。 // components,发送消息附带参数。 // reserved:为头部预留的字节数 [self.vcPort sendBeforeDate:[NSDate date] msgid:10086 components:array from:self.myPort reserved:0]; } #pragma mark - NSMachPortDelegate - (void)handlePortMessage:(NSPortMessage *)message{ NSLog(@"KCPerson 收到从 PortViewController 传过来一些信息:\n"); NSLog(@"components == %@",[message valueForKey:@"components"]); NSLog(@"receivePort == %@",[message valueForKey:@"receivePort"]); NSLog(@"sendPort == %@",[message valueForKey:@"sendPort"]); NSLog(@"msgid == %@",[message valueForKey:@"msgid"]); } 复制代码
打印结果:
能够将打印结果对比着代码看,就一目了然