**擴展:**蘋果是單進程,沙盒資源會更安全,切換進程消耗資源會特別大,因此採用單進程體驗更流暢安全
拓展: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"]); } 複製代碼
打印結果:
能夠將打印結果對比着代碼看,就一目瞭然