RunLoop

Runloop作用

  • 1.保證當(dāng)前線程不退出印衔。
  • 2.監(jiān)聽(tīng)事件:觸摸事件啡捶、時(shí)鐘事件和網(wǎng)絡(luò)事件。
  • 3.節(jié)約資源:有事件時(shí)奸焙,處理事件瞎暑。沒(méi)有事件,處于休眠狀態(tài)与帆。

ps:事件產(chǎn)生到有結(jié)果的過(guò)程:
硬件設(shè)備接收信號(hào) > 電信號(hào)轉(zhuǎn)化成模擬信號(hào) > 操作系統(tǒng)接收信號(hào) > 找到響應(yīng)的應(yīng)用程序 > 找到具體的某個(gè)類(lèi)的某個(gè)方法執(zhí)行了赌。

時(shí)鐘事件和Runloop關(guān)系

案列一:

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
}

- (void)timerMethod {
    static int a = 0;
    NSLog(@"%d---%@",a,[NSThread currentThread]);
}

該方法已經(jīng)將時(shí)鐘事件添加到當(dāng)前Runloop中,無(wú)需程序員操作什么玄糟。只是此時(shí)Runloop模式是默認(rèn)模式勿她。
案列二:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]addTimer:timer forMode: NSRunLoopCommonModes];
}

- (void)timerMethod {
    static int a = 0;
    NSLog(@"%d---%@",a,[NSThread currentThread]);
}

該方法返回一個(gè)NSTimer對(duì)象,通過(guò)加入到Runloop的占位模式下阵翎,開(kāi)啟定時(shí)服務(wù)逢并。

Runloop的常見(jiàn)模式

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
    默認(rèn)模式,APP主線程是在該模式下運(yùn)行贮喧。
  • UITrackingRunLoopMode
    UI模式筒狠,ScrollView滑動(dòng)時(shí)的模式,其優(yōu)先級(jí)高于默認(rèn)模式箱沦。
  • UIInitializationRunLoopMode
    啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode辩恼,啟動(dòng)完成后就不再使用。
  • NSRunLoopCommonModes(kCFRunLoopCommonModes)
    占位模式谓形,包含默認(rèn)模式和UI模式灶伊。
  • 更多模式

蘋(píng)果公開(kāi)提供的 Mode 有三個(gè):

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
  • UITrackingRunLoopMode
  • NSRunLoopCommonModes(kCFRunLoopCommonModes)

note:Runloop在同一段時(shí)間只能并且必須在一種特定的Mode下運(yùn)行。更換mode時(shí)寒跳,需要停止當(dāng)前Loop聘萨,然后重啟新Loop。

理解ibireme 深入理解RunLoopRunLoop 的 Mode:

個(gè)人理解_commonModes和_commonModeItems關(guān)系:
以Timer在默認(rèn)模式和UI模式(即占位模式)下為例童太。主線程的 RunLoop 里有兩個(gè)預(yù)置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode米辐。這兩個(gè) Mode 都已經(jīng)被標(biāo)記為”Common”屬性,就是說(shuō)這兩個(gè)Mode已經(jīng)被添加到_commonModes中书释,并且Timer這個(gè)item已經(jīng)被加到_commonModeItems中翘贮。當(dāng)滑動(dòng)Scrollview時(shí),Runloop會(huì)退出爆惧,重新指定Mode為UI模式狸页,再次開(kāi)啟Runloop悼院,RunLoop 會(huì)自動(dòng)將 _commonModeItems 里的Timer 同步到具有 “Common” 標(biāo)記的所有Mode里锨用。

問(wèn)題探索

問(wèn)題一:

為哈蘋(píng)果建議時(shí)鐘事件添加到Runloop的默認(rèn)模式下,而不放到UI模式中呢既绕?

舉個(gè)例子:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop]addTimer:timer forMode:UITrackingRunLoopMode];
}

- (void)timerMethod {
    sleep(1.0);
    static int a = 0;
    NSLog(@"%d---%@",a,[NSThread currentThread]);
}

如果時(shí)鐘事件添加到UI模式下糖驴,在timer的回調(diào)方法中添加一個(gè)耗時(shí)操作蜘欲,會(huì)阻塞主線程章姓,出現(xiàn)UI卡頓啥刻。

問(wèn)題二:

開(kāi)啟一條子線程,執(zhí)行放到RunLoop中的timer定時(shí)器窃页,定時(shí)器的seletor為什么不執(zhí)行跺株?

代碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    }];
    [thread start];
}

- (void)timerMethod{
    static NSInteger count = 0;
    NSLog(@"count = %ld",count ++);
}

原因:子線程死掉复濒,NSthread負(fù)責(zé)開(kāi)辟一條線程脖卖,CPU負(fù)責(zé)調(diào)度線程,線程中任務(wù)一旦執(zhí)行完成就會(huì)釋放巧颈,若想保住子線程畦木,開(kāi)啟一個(gè)死循環(huán)。

代碼修改如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
        while (true) {
            
        }
    }];
    [thread start];
}

- (void)timerMethod{
    static NSInteger count = 0;
    NSLog(@"count = %ld",count ++);
}

雖然開(kāi)啟一個(gè)死循環(huán)保住了子線程砸泛,此時(shí)的timerMethod方法依然沒(méi)有執(zhí)行十籍,為什么?

原因:雖然在子線程中把timer放到RunLoop中唇礁,也保住了子線程勾栗,但是死循環(huán)中并沒(méi)有操作什么,需要的是把子線程的RunLoop并沒(méi)有從Event隊(duì)列(消息隊(duì)列)中取出處理盏筐。

代碼再次修改如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop]run];
    }];
    [thread start];
}

- (void)timerMethod{
    static NSInteger count = 0;
    NSLog(@"count = %ld",count ++);
}

如果需要手動(dòng)停止這個(gè)線程围俘?
代碼三次修改如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    isFinished = YES;
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
        while (isFinished) {
            [[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0001]];
        }
    }];
    [thread start];
}

- (void)timerMethod{
    static NSInteger count = 0;
    NSLog(@"count = %ld",count ++);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    isFinished = NO;
}

上述代碼中為什么Runloop模式都是NSDefaultRunLoopMode?
原因:在子線程中使用默認(rèn)模式琢融,就可以界牡,沒(méi)有必要使用占位模式,子線程中使用默認(rèn)模式并不會(huì)阻塞主線程漾抬。

問(wèn)題三:

每一條線程都有一個(gè)runloop這種說(shuō)法對(duì)嗎宿亡?

不對(duì),原因:創(chuàng)建了一個(gè)線程纳令,RunLoop并未創(chuàng)建挽荠,但是當(dāng)你第一次獲取時(shí),就會(huì)創(chuàng)建一個(gè)RunLoop平绩, 再次獲取時(shí)圈匆,拿到的只是第一次獲取的RunLoop。(有點(diǎn)類(lèi)似于懶加載)當(dāng)線程退出([NSThread exit], RunLoop釋放馒过。

問(wèn)題四:

主線程退出臭脓,對(duì)子線程有影響嗎?

沒(méi)有腹忽,主線程也是一條線程来累,主線程死掉砚作,子線程依然可以正常運(yùn)行。

問(wèn)題五:

主線程為什么只有一個(gè)嘹锁?

原因:線程之間訪問(wèn)資源存在資源搶奪的問(wèn)題葫录,假如存在兩條線程就需要對(duì)同一個(gè)資源進(jìn)行加鎖,這樣APP的流暢性就會(huì)降低领猾,所以只會(huì)開(kāi)辟一條主線程米同。

問(wèn)題擴(kuò)展一:

NSTimer定時(shí)器時(shí)間不精確原因?

一個(gè)循環(huán)中如果RunLoop沒(méi)有被識(shí)別(這個(gè)時(shí)間大概在50-100ms)或者說(shuō)當(dāng)前RunLoop在執(zhí)行一個(gè)長(zhǎng)的call out(例如執(zhí)行某個(gè)循環(huán)操作)則NSTimer可能就會(huì)存在誤差摔竿,RunLoop在下一次循環(huán)中繼續(xù)檢查并根據(jù)情況確定是否執(zhí)行面粮。

問(wèn)題擴(kuò)展二:

performSelector:withObject:afterDelay:本質(zhì)?

performSelector:withObject:afterDelay:執(zhí)行的本質(zhì)還是通過(guò)創(chuàng)建一個(gè)NSTimer然后加入到當(dāng)前線程RunLoop继低。(類(lèi)似的還有performSelector:onThread:withObject:afterDelay:熬苍,只是它會(huì)在另一個(gè)線程的RunLoop中創(chuàng)建一個(gè)Timer),所以此方法事實(shí)上在任務(wù)執(zhí)行完之前會(huì)對(duì)觸發(fā)對(duì)象形成引用袁翁,任務(wù)執(zhí)行完進(jìn)行釋放(注意:performSelector: withObject:等方法則等同于直接調(diào)用柴底,原理與此不同)。

相應(yīng)的方法還有:

performSelector:withObject:afterDelay:
performSelector:withObject:afterDelay:inModes:

針對(duì)下面的幾個(gè)方法粱胜,則是創(chuàng)建了一個(gè)source0事件柄驻。

performSelectorOnMainThread:withObject:waitUntilDone:
performSelectorOnMainThread:withObject:waitUntilDone:modes:

performSelector:onThread:withObject:waitUntilDone:
performSelector:onThread:withObject:waitUntilDone:modes:

擴(kuò)展問(wèn)題來(lái)自: iOS刨根問(wèn)底-深入理解RunLoop

觸摸事件與Runloop

觸摸事件又叫事件源(輸入源),對(duì)應(yīng)于coreFoundation框架中的CFRunLoopSourceRef焙压。

事件源分類(lèi)
  • source0:非基于Port的,用于用戶主動(dòng)觸發(fā)的事件鸿脓。諸如UIEvent(觸摸,滑動(dòng)等)冗恨,performSelector這種需要手動(dòng)觸發(fā)的操作答憔。
  • source1:基于Port的系統(tǒng)內(nèi)核事件,可以通過(guò)內(nèi)核和其他線程相互發(fā)送消息 掀抹。

問(wèn)題六:

線程之間怎么進(jìn)行通訊虐拓?
- (void)viewDidLoad {
    [super viewDidLoad];
    isFinished = YES;
}

- (void)timerMethod{
    static NSInteger count = 0;
    NSLog(@"count = %ld",count ++);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSThread *thread = [[NSThread alloc]initWithBlock:^{
        while (isFinished) {
            [[NSRunLoop currentRunLoop]run];
        }
    }];
    [thread start];
    [self performSelector:@selector(otherMethod) onThread:thread withObject:nil waitUntilDone:NO];
}

- (void)otherMethod {
    for (NSInteger i = 0; i < 10; i++) {
        NSLog(@"i = %ld currentThread = %@",i,[NSThread currentThread]);
    }
    isFinished = NO;
}

線程之間通過(guò)Source事件進(jìn)行通訊。

CFRunloopObserverRef與Runloop

CFRunLoopObserverRef是觀察者,能夠監(jiān)聽(tīng)RunLoop的狀態(tài)改變傲武。

可以監(jiān)聽(tīng)的狀態(tài)有:

 /* Run Loop Observer Activities */  
  typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {  
  kCFRunLoopEntry = (1UL << 0),             //即將進(jìn)入RunLoop  
  kCFRunLoopBeforeTimers = (1UL << 1),      //即將處理Timer  
  kCFRunLoopBeforeSources = (1UL << 2),     //即將處理Source  
  kCFRunLoopBeforeWaiting = (1UL << 5),     //即將進(jìn)入休眠  
  kCFRunLoopAfterWaiting = (1UL << 6),      //剛從休眠中喚醒  
  kCFRunLoopExit = (1UL << 7),              //即將推出RunLoop  
  kCFRunLoopAllActivities = 0x0FFFFFFFU  
  };

問(wèn)題七

autoreleasepool什么時(shí)候釋放蓉驹?

盜用一張圖,看一下Runloop內(nèi)部邏輯:


上圖地址

  • 即將進(jìn)入Loop揪利,其會(huì)調(diào)用 _objc_autoreleasePoolPush() 創(chuàng)建自動(dòng)釋放池态兴。
  • BeforeWaiting(準(zhǔn)備進(jìn)入休眠) 時(shí)調(diào)用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 釋放舊的池并創(chuàng)建新池;Exit(即將退出Loop) 時(shí)調(diào)用 _objc_autoreleasePoolPop() 來(lái)釋放自動(dòng)釋放池疟位。
    ps:?jiǎn)栴}七答案可以在ibireme 深入理解RunLoop找到瞻润。

問(wèn)題八

AFNetworking為什么要有一個(gè)常駐線程?

使用NSURLConnection有幾種選擇:

A.在主線程調(diào)異步接口
若直接在主線程調(diào)用異步接口,會(huì)有個(gè)Runloop相關(guān)的問(wèn)題:當(dāng)在主線程調(diào)用 [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES] 時(shí)绍撞,請(qǐng)求發(fā)出正勒,偵聽(tīng)任務(wù)會(huì)加入到主線程的 Runloop 下,RunloopMode 會(huì)默認(rèn)為 NSDefaultRunLoopMode傻铣。這表明只有當(dāng)前線程的Runloop 處于 NSDefaultRunLoopMode 時(shí)章贞,這個(gè)任務(wù)才會(huì)被執(zhí)行。但當(dāng)用戶滾動(dòng) tableview 或 scrollview 時(shí)非洲,主線程的 Runloop 是處于 NSEventTrackingRunLoopMode 模式下的鸭限,不會(huì)執(zhí)行 NSDefaultRunLoopMode 的任務(wù),所以會(huì)出現(xiàn)一個(gè)問(wèn)題两踏,請(qǐng)求發(fā)出后败京,如果用戶一直在操作UI上下滑動(dòng)屏幕,那在滑動(dòng)結(jié)束前是不會(huì)執(zhí)行回調(diào)函數(shù)的缆瓣,只有在滑動(dòng)結(jié)束喧枷,RunloopMode 切回 NSDefaultRunLoopMode,才會(huì)執(zhí)行回調(diào)函數(shù)弓坞。蘋(píng)果一直把動(dòng)畫(huà)效果性能放在第一位,估計(jì)這也是蘋(píng)果提升UI動(dòng)畫(huà)性能的手段之一车荔。
所以若要在主線程使用 NSURLConnection 異步接口渡冻,需要手動(dòng)把 RunloopMode 設(shè)為 NSRunLoopCommonModes。這個(gè) mode 意思是無(wú)論當(dāng)前 Runloop 處于什么狀態(tài)忧便,都執(zhí)行這個(gè)任務(wù)族吻。

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 
[connection start]; 

B.在子線程調(diào)同步接口
若在子線程調(diào)用同步接口,一條線程只能處理一個(gè)請(qǐng)求珠增,因?yàn)檎?qǐng)求一發(fā)出去線程就阻塞住等待回調(diào)超歌,需要給每個(gè)請(qǐng)求新建一個(gè)線程,這是很浪費(fèi)的蒂教,這種方式唯一的好處應(yīng)該是易于控制請(qǐng)求并發(fā)的數(shù)量巍举。

C.在子線程調(diào)異步接口
子線程調(diào)用異步接口,子線程需要有 Runloop 去接收異步回調(diào)事件凝垛,這里也可以每個(gè)請(qǐng)求都新建一條帶有 Runloop 的線程去偵聽(tīng)回調(diào)懊悯,但這一點(diǎn)好處都沒(méi)有,既然是異步回調(diào)梦皮,除了處理回調(diào)內(nèi)容炭分,其他時(shí)間線程都是空閑可利用的,所有請(qǐng)求共用一個(gè)響應(yīng)的線程就夠了剑肯。

AFNetworking 用的就是第三種方式捧毛,創(chuàng)建了一條常駐線程專(zhuān)門(mén)處理所有請(qǐng)求的回調(diào)事件,這個(gè)模型跟 nodejs 有點(diǎn)類(lèi)似。網(wǎng)絡(luò)請(qǐng)求回調(diào)處理完呀忧,組裝好數(shù)據(jù)后再給上層調(diào)用者回調(diào)型将,這時(shí)候回調(diào)是拋回主線程的,因?yàn)橹骶€程是最安全的荐虐,使用者可能會(huì)在回調(diào)中更新UI七兜,在子線程更新UI會(huì)導(dǎo)致各種問(wèn)題,一般使用者也可以不需要關(guān)心線程問(wèn)題福扬。
答案來(lái)自這里:AFNetworking2.0的源碼解析

問(wèn)題九

怎么創(chuàng)建一個(gè)常駐線程腕铸?

參考ibireme 深入理解RunLoop

Runloop應(yīng)用

iOS實(shí)時(shí)卡頓監(jiān)控

推薦文章:

ibireme 深入理解RunLoop
iOS線下分享《RunLoop》by 孫源@sunnyxx
黑幕背后的Autorelease by sunnyxx
iOS Runloop實(shí)踐(常駐線程)
iOS刨根問(wèn)底-深入理解RunLoop
Runloop應(yīng)用舉例
iOS RunLoop入門(mén)小結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市铛碑,隨后出現(xiàn)的幾起案子狠裹,更是在濱河造成了極大的恐慌,老刑警劉巖汽烦,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涛菠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡撇吞,警方通過(guò)查閱死者的電腦和手機(jī)俗冻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牍颈,“玉大人迄薄,你說(shuō)我怎么就攤上這事≈笏辏” “怎么了讥蔽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)画机。 經(jīng)常有香客問(wèn)我冶伞,道長(zhǎng),這世上最難降的妖魔是什么步氏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任响禽,我火速辦了婚禮,結(jié)果婚禮上戳护,老公的妹妹穿的比我還像新娘金抡。我一直安慰自己,他們只是感情好腌且,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布梗肝。 她就那樣靜靜地躺著,像睡著了一般铺董。 火紅的嫁衣襯著肌膚如雪巫击。 梳的紋絲不亂的頭發(fā)上禀晓,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音坝锰,去河邊找鬼粹懒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛顷级,可吹牛的內(nèi)容都是我干的凫乖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼弓颈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帽芽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起翔冀,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤导街,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后纤子,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搬瑰,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年控硼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泽论。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡象颖,死狀恐怖佩厚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情说订,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布潮瓶,位于F島的核電站陶冷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏毯辅。R本人自食惡果不足惜埂伦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望思恐。 院中可真熱鬧沾谜,春花似錦、人聲如沸胀莹。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)描焰。三九已至媳否,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背篱竭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工力图, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人掺逼。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓吃媒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親吕喘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赘那,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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