iOS 創(chuàng)建常駐線程

iOS中默認就有個主線程即mainThread祖能,我們的UI線程指的就是主線程媚媒,一般都是在主線程中操作UI搏色,從某個角度來講,我們的主線程就是一個常駐線程捏肢。

一般情況下,我們開啟一個子線程饥侵,讓子線程去跑一個任務鸵赫,當任務執(zhí)行完畢之后,該線程就會被系統(tǒng)自動銷毀躏升。假如說 在一個遍歷循環(huán)中辩棒,要執(zhí)行10000次創(chuàng)建子線程去執(zhí)行一個耗時任務,那么這么頻繁的去創(chuàng)建和銷毀線程就會造成資源的浪費膨疏,那我們?yōu)槭裁床蛔岊l繁使用的子線程常駐在內(nèi)存中一睁,想用的時候就用,不想用的時候讓他休眠呢成肘?

接下來就示例創(chuàng)建一個常駐線程卖局。

  • 首先創(chuàng)建一個ThreadManager類,為類添加一個暴露類屬性双霍,一個隱私類屬性:
@interface ThreadManager : NSObject
@property (nonatomic, assign, class) BOOL isShouldKeepRunning;
@end
@interface ThreadManager()
@property (nonatomic, strong, class) NSThread * residentThread;
@end

其中isShouldKeepRuning屬性可以用來控制當前子線程中runloop是否停止
residentThread為要創(chuàng)建引用的常駐線程

  • 接下來 聲明一個靜態(tài)變量砚偶,開辟空間
static BOOL _isShouldKeepRuning;
static NSThread * _residentThread;

為其提供getter和setter方法

+ (BOOL)isShouldKeepRunning {
    return _isShouldKeepRuning;
}

+ (void)setIsShouldKeepRunning:(BOOL)isShouldKeepRunning {
    _isShouldKeepRuning = isShouldKeepRunning;
}

+ (NSThread *)residentThread {
    if (_residentThread == nil) {
        // thread方法為創(chuàng)建線程的方法,下面會寫到洒闸。
        _residentThread = [self thread];
    }
    return _residentThread;
}

+ (void)setResidentThread:(NSThread *)residentThread {
    _residentThread = residentThread;
}

提供線程創(chuàng)建的方法 以及在子線程中獲取runloop

+ (NSThread *)thread {
    NSThread * thread = nil;
    __weak typeof(self)weakSelf = self;
    void(^creatThreadBlock)(void) = ^{
        NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
        [currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
        while (weakSelf && weakSelf.isShouldKeepRunning) {
            [currentLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
        NSLog(@"runloop 停止染坯! ! 丘逸!");
    };
    self.isShouldKeepRunning = YES;
    if (@available(iOS 10.0, *)) {
        thread = [[NSThread alloc] initWithTarget:self selector:@selector(creatThreadMethod:) object:creatThreadBlock];
    } else {
        thread = [[NSThread alloc] initWithBlock:creatThreadBlock];
    }
    thread.name = @"thread_resident";
    [thread start];
    return thread;
}

+ (void)creatThreadMethod:(void(^)(void))task {
    if (task) {
        task();
    }
}

+ (void)executeTask:(void(^)(void))task {
    [self performSelector:@selector(threadTaskMethod:) onThread:self.residentThread withObject:task waitUntilDone:NO];
}

+ (void)threadTaskMethod:(void(^)(void))task {
    if (task) {
        NSLog(@"currentThread: %@", [NSThread currentThread]);
        task();
    }
}

其中

NSRunLoop * currentLoop = [NSRunLoop currentRunLoop];
[currentLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
  • RunLoop只能獲取单鹿,不能創(chuàng)建。 在子線程中深纲,獲取runloop仲锄,如果沒有, 系統(tǒng)會為我們創(chuàng)建湃鹊,如果currentLoop中沒有 source0事件儒喊、source1事件、定時器币呵、obsever 這些事件資源怀愧,那么RunLoop不會循環(huán),會直接結束,所以要給RunLoop加一個監(jiān)聽端口芯义,用來監(jiān)聽系統(tǒng)事件的發(fā)生哈垢,那么這樣子才能夠保證RunLoop一直循環(huán)不退出。
  • 最后將+ (void)executeTask:(void(^)(void))task; 方法暴露出來扛拨,外部就可以直接拿來使用耘分。下面是我測試的代碼和測試結果
 [ThreadManager executeTask:^{
        NSLog(@"1 1 1 子線程 執(zhí)行操作 ");
    }];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"2 2 2 子線程 執(zhí)行操作 ");
        }];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"3 3 3 子線程 執(zhí)行操作 ");
        }];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        ThreadManager.isShouldKeepRunning = NO;
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [ThreadManager executeTask:^{
            NSLog(@"4 4 4 子線程 執(zhí)行操作 ");
        }];
    });

結果如下:


常駐線程執(zhí)行
  • 可見任務的執(zhí)行都在同一個子線程當中,當改變isShouldKeepRunning的值鬼癣,在下一次RunLoop循環(huán)的時候陶贼,RunLoop循環(huán)被打破,退出RunLoop待秃,此時常駐線程也不復存在。
  • 后續(xù)也可以再擴展一個方法用來重新掉起一條新的常駐線程痹屹,那么可以達到在某些情況下章郁,已經(jīng)執(zhí)行了很多任務,用不到這個線程志衍,不想讓這個線程在內(nèi)存中存在暖庄,手動給銷毀掉,在用到的時候 重新創(chuàng)建楼肪。
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末培廓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子春叫,更是在濱河造成了極大的恐慌肩钠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暂殖,死亡現(xiàn)場離奇詭異价匠,居然都是意外死亡,警方通過查閱死者的電腦和手機呛每,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門踩窖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晨横,你說我怎么就攤上這事洋腮。” “怎么了手形?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵啥供,是天一觀的道長。 經(jīng)常有香客問我叁幢,道長滤灯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮鳞骤,結果婚禮上窒百,老公的妹妹穿的比我還像新娘。我一直安慰自己豫尽,他們只是感情好篙梢,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著美旧,像睡著了一般渤滞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上榴嗅,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天妄呕,我揣著相機與錄音,去河邊找鬼嗽测。 笑死绪励,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的唠粥。 我是一名探鬼主播疏魏,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晤愧!你這毒婦竟也來了大莫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤官份,失蹤者是張志新(化名)和其女友劉穎只厘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贯吓,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡懈凹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了悄谐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片介评。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖爬舰,靈堂內(nèi)的尸體忽然破棺而出们陆,到底是詐尸還是另有隱情,我是刑警寧澤情屹,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布坪仇,位于F島的核電站,受9級特大地震影響垃你,放射性物質發(fā)生泄漏椅文。R本人自食惡果不足惜喂很,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皆刺。 院中可真熱鬧少辣,春花似錦、人聲如沸羡蛾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽痴怨。三九已至忙干,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浪藻,已是汗流浹背捐迫。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爱葵,地道東北人弓乙。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像钧惧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子勾习,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容