07iOS應(yīng)用程序的生命周期

0. 引子

iOS應(yīng)用程序一般都是由自己編寫的代碼系統(tǒng)框架(system frameworks)組成,系統(tǒng)框架提供一些基本infrastructure給所有app來(lái)運(yùn)行,而你提供自己編寫的代碼來(lái)定制app的外觀和行為。因此,了解iOS infrastructure和它們?nèi)绾喂ぷ鲗?duì)編寫app是很有幫助的。

1. Main函數(shù)入口

所有基于C編寫的app的入口都是main
函數(shù),但iOS應(yīng)用程序有點(diǎn)不同。不同就是你不需要為iOS應(yīng)用程序而自己編寫main
函數(shù),當(dāng)你使用Xcode創(chuàng)建工程的時(shí)候就已經(jīng)提供了。除非一些特殊情況,否則你不應(yīng)該修改Xcode提供的main
函數(shù)實(shí)現(xiàn)。示例代碼如下:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[])
{ 
     @autoreleasepool { 
           return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 
     } 
}

上面實(shí)例代碼中有一個(gè)很重要的函數(shù)UIApplicationMain,它主要是創(chuàng)建app的幾個(gè)核心對(duì)象來(lái)處理以下過(guò)程:

  • 1.從可用Storyboard文件加載用戶界面
  • 2.調(diào)用AppDelegate自定義代碼來(lái)做一些初始化設(shè)置
  • 3.將app放入Main Run Loop環(huán)境中來(lái)響應(yīng)和處理與用戶交互產(chǎn)生的事件

2.應(yīng)用程序的架構(gòu)

2.1 MVC

iOS應(yīng)用程序都遵循Model-View-Controller
的架構(gòu),Model負(fù)責(zé)存儲(chǔ)數(shù)據(jù)和處理業(yè)務(wù)邏輯,View負(fù)責(zé)顯示數(shù)據(jù)和與用戶交互,Controller是兩者的中介,協(xié)調(diào)Model和View
相互協(xié)作。它們的通訊規(guī)則如下:

  • 1.Controller能夠訪問(wèn)Model和View,Model和View不能互相訪問(wèn)
MVC
  • 2.當(dāng)View與用戶交互產(chǎn)生事件時(shí),使用target-action方式來(lái)處理
Stanford University
  • 3.當(dāng)View需要處理一些特殊UI邏輯或獲取數(shù)據(jù)源時(shí),通過(guò)delegate或data source方式交給Controller來(lái)處理
View
  • 4.Model不能直接與Controller通信,當(dāng)Model有數(shù)據(jù)更新時(shí),可以通過(guò)Notification或KVO (Key Value Observing)來(lái)通知Controller更新View
Model

2.2 幾個(gè)關(guān)鍵對(duì)象

了解iOS的MVC設(shè)計(jì)模式之后,我們從下圖來(lái)了解在MVC模式下iOS應(yīng)用程序有哪些關(guān)鍵對(duì)象以及它們職責(zé)主要是什么?

The Structure of an App
  • 1.UIApplication對(duì)象
    用戶與iOS設(shè)備交互時(shí)產(chǎn)生的事件(Multitouch Events,Motion Event,Remote Control Event)交由UIApplication
    對(duì)象來(lái)分發(fā)給control objects(UIControl)對(duì)應(yīng)的target objects來(lái)處理并且管理整個(gè)事件循環(huán),而一些關(guān)于app運(yùn)行時(shí)重要事件委托給app delegate
    來(lái)處理。

  • 2.App delegate對(duì)象
    App delegate對(duì)象遵循UIApplicationDelegate
    協(xié)議,響應(yīng)app運(yùn)行時(shí)重要事件(app啟動(dòng)、app內(nèi)存不足、app終止、切換到另一個(gè)app、切回app),主要用于app在啟動(dòng)時(shí)初始化一些重要數(shù)據(jù)結(jié)構(gòu);例如,初始化UIWindow,設(shè)置一些屬性,為window添加rootViewController。

  • 3.View controller對(duì)象
    View Controller有一個(gè)view屬性是view層次結(jié)構(gòu)中的根view,你可以添加子view來(lái)構(gòu)建復(fù)雜的view;controller有一些viewDidLoad、viewWillAppear等方法來(lái)管理view的生命周期;由于它繼承UIResponder,所有還會(huì)響應(yīng)和處理用戶事件。

  • 4.Documents和data model對(duì)象
    data model對(duì)象主要用來(lái)存儲(chǔ)數(shù)據(jù)。例如,餓了么app在搜索切換地址后,有歷史記錄搜索地址歷史,當(dāng)app下次啟動(dòng)時(shí),讀取和顯示搜索地址歷史。document對(duì)象(繼承UIDocument)用來(lái)管理一些或所有的data model對(duì)象。document對(duì)象并不是必須的,但提供一種方便的方式來(lái)分組屬于單個(gè)文件或多個(gè)文件的數(shù)據(jù)。

  • 5.UIWindow對(duì)象UIWindow
    對(duì)象位于view層次結(jié)構(gòu)中的最頂層,它充當(dāng)一個(gè)基本容器而不顯示內(nèi)容,如果想顯示內(nèi)容,添加一個(gè)content view到window。它也是繼承UIResponder
    ,所以它也是會(huì)響應(yīng)和處理用戶事件。

  • 6.Viewcontrollayer對(duì)象
    View對(duì)象可以通過(guò)addSubview和removeFromSuperview 等方法管理view的層次結(jié)構(gòu),使用layoutIfNeeded和setNeedsLayout等方法布局view的層次結(jié)構(gòu),當(dāng)你發(fā)現(xiàn)系統(tǒng)提供view已經(jīng)滿足不了你想要的外觀需求時(shí),可以重寫drawRect方法或通過(guò)layer屬性來(lái)構(gòu)造復(fù)雜的圖形外觀和動(dòng)畫。還有一點(diǎn),UIView也是繼承UIResponder,所以也能夠處理用戶事件
    Control對(duì)象通常就是處理特定類型用戶交互的View,常用的有button、switch、text field等。
    除了使用View和Control來(lái)構(gòu)建view層次結(jié)構(gòu)來(lái)影響app外觀之外,還可以使用Core Animation框架的Layer對(duì)象來(lái)渲染view外觀和構(gòu)建復(fù)雜的動(dòng)畫。

3. Main Run Loop

一個(gè)iOS應(yīng)用程序的main run loop主要作用是處理所有與用戶相關(guān)的事件。UIApplication對(duì)象在啟動(dòng)時(shí)就設(shè)置main run loop和使用它來(lái)處理事件和更新基于view的界面。正如它名字所示,main run loop是運(yùn)行在應(yīng)用程序的主線程。這樣就確保與接收到用戶相關(guān)的事件被有序地處理。

下圖顯示main run loop的架構(gòu)和用戶事件最終是怎樣被應(yīng)用程序處理。當(dāng)用戶與設(shè)備交互時(shí),系統(tǒng)就會(huì)生成與交互關(guān)聯(lián)的事件,然后被應(yīng)用程序的UIKit通過(guò)一個(gè)特殊的端口來(lái)分發(fā)。應(yīng)用程序把事件放入隊(duì)列,然后逐個(gè)分發(fā)到main run loop來(lái)執(zhí)行。UIApplication
對(duì)象是第一個(gè)對(duì)象接收到事件,然后決定怎樣處理它。一個(gè)touch event通常都被分發(fā)到main window對(duì)象,然后依次分發(fā)到發(fā)生觸碰的view。其他event的接收事件對(duì)象路徑可能有點(diǎn)不同。

進(jìn)程

大多數(shù)的事件通過(guò)使用main run loop來(lái)分發(fā),但有些不是。有些事件被發(fā)送到一個(gè)delegate對(duì)象或傳遞到你提供的block中。想了解更多如何處理大多數(shù)類型的事件,其中包括touch、remote control、motion、accelerometer和gyroscopic等事件,請(qǐng)查閱Event Handle Guide for iOS

4. 應(yīng)用程序的狀態(tài)和多任務(wù)

4.1

有時(shí)系統(tǒng)會(huì)從app一種狀態(tài)切換另一種狀態(tài)來(lái)響應(yīng)系統(tǒng)發(fā)生的事件。例如,當(dāng)用戶按下home鍵、電話打入、或其他中斷發(fā)生時(shí),當(dāng)前運(yùn)行的應(yīng)用程序會(huì)切換狀態(tài)來(lái)響應(yīng)。應(yīng)用程序的狀態(tài)有以下幾種:

App狀態(tài)切換
  • Not running:app還沒(méi)運(yùn)行
  • Inactive:app運(yùn)行在foreground但沒(méi)有接收事件
  • Active:app運(yùn)行在foreground和正在接收事件
  • Background:運(yùn)行在background和正在執(zhí)行代碼
  • Suspended:運(yùn)行在background但沒(méi)有執(zhí)行代碼

4.2

大多數(shù)發(fā)生狀態(tài)轉(zhuǎn)換時(shí)都會(huì)調(diào)用delegate對(duì)象對(duì)應(yīng)的方法來(lái)響應(yīng)app的狀態(tài)改變。下面匯總了delegate對(duì)象的所有方法,當(dāng)app狀態(tài)發(fā)生轉(zhuǎn)換時(shí),你可能會(huì)使用到它們。

  • application:willFinishLaunchingWithOptions: - 這個(gè)方法是你在啟動(dòng)時(shí)的第一次機(jī)會(huì)來(lái)執(zhí)行代碼
  • application:didFinishLaunchingWithOptions: - 這個(gè)方法允許你在顯示app給用戶之前執(zhí)行最后的初始化操作
  • applicationDidBecomeActive: - app已經(jīng)切換到active狀態(tài)后需要執(zhí)行的操作
  • applicationWillResignActive: - app將要從前臺(tái)切換到后臺(tái)時(shí)需要執(zhí)行的操作
  • applicationDidEnterBackground: - app已經(jīng)進(jìn)入后臺(tái)后需要執(zhí)行的操作
  • applicationWillEnterForeground: - app將要從后臺(tái)切換到前臺(tái)需要執(zhí)行的操作,但app還不是active狀態(tài)
  • applicationWillTerminate: - app將要結(jié)束時(shí)需要執(zhí)行的操作

4.3

現(xiàn)在講下app啟動(dòng)、來(lái)回切換app和鎖屏?xí)r狀態(tài)的切換和調(diào)用對(duì)應(yīng)哪些delegate對(duì)象的方法:

  • app啟動(dòng)和active/inactive
    圖1

如圖所示,當(dāng)app啟動(dòng)時(shí),首先由not running狀態(tài)切換到inactive狀態(tài),此時(shí)調(diào)用application:didFinishLaunchingWithOptions:方法;然后由inactive狀態(tài)切換到active狀態(tài),此時(shí)調(diào)用applicationDidBecomeActive:方法。

圖2

當(dāng)app發(fā)生中斷時(shí),由active狀態(tài)切換到inactive狀態(tài),此時(shí)調(diào)用applicationWillResignActive:方法。

  • 來(lái)回切換app
    圖3

如圖所示,當(dāng)切換到另一個(gè)app時(shí),由狀態(tài)active切換到inactive,此時(shí)調(diào)用applicationWillResignActive:方法;然后從inactive狀態(tài)切換到running狀態(tài),此時(shí)調(diào)用applicationDidEnterBackground:方法。

圖4

而當(dāng)切換回本來(lái)的app時(shí),由running狀態(tài)切換到inactive狀態(tài),此時(shí)調(diào)用applicationWillEnterForeground:方法,然后由inactive狀態(tài)切換到active狀態(tài),調(diào)用applicationDidBecomeActive:方法。

  • 鎖屏
    圖5

如何所示,當(dāng)手機(jī)鎖屏?xí)r,由狀態(tài)active
切換到inactive
,此時(shí)調(diào)用applicationWillResignActive:
;然后再由inactive
狀態(tài)切換到running
狀態(tài),此時(shí)調(diào)用applicationDidEnterBackground:
方法。
更多關(guān)于app狀態(tài)切換以及調(diào)用app delegate
哪些方法,請(qǐng)觀看WWDC 2011 Session的session_320__adopting_multitasking_in_your_app視頻。

5. 應(yīng)用程序的終止

系統(tǒng)常常是為其他app啟動(dòng)時(shí)由于內(nèi)存不足而回收內(nèi)存最后需要終止應(yīng)用程序,但有時(shí)也會(huì)是由于app很長(zhǎng)時(shí)間才響應(yīng)而終止。如果app當(dāng)時(shí)運(yùn)行在后臺(tái)并且沒(méi)有暫停,系統(tǒng)會(huì)在應(yīng)用程序終止之前調(diào)用applicationWillTerminate:來(lái)保存用戶的一些重要數(shù)據(jù)以便下次啟動(dòng)時(shí)恢復(fù)到app原來(lái)的狀態(tài)。

6. 總結(jié)

本文總結(jié)了iOS應(yīng)用程序從啟動(dòng)到結(jié)束過(guò)程中有哪些關(guān)鍵對(duì)象在參與,以及當(dāng)用戶與系統(tǒng)交互時(shí)產(chǎn)生事件時(shí),系統(tǒng)利用main run loop來(lái)管理事件循環(huán),決定將事件交給系統(tǒng)哪些對(duì)象處理和如何處理。而當(dāng)app啟動(dòng)、來(lái)回切換app和鎖屏?xí)r,app的狀態(tài)如何切換和調(diào)用對(duì)應(yīng)的哪些app delegate對(duì)象來(lái)處理。

7. 擴(kuò)展閱讀

App Programming Guide for iOS
Developing iOS 7 App for iPhone and iPad
深入理解RunLoop
Objective-C Autorelease Pool 的實(shí)現(xiàn)原理

20180322iOS應(yīng)用生命周期總結(jié)

應(yīng)用程序的狀態(tài):

  • Not running未運(yùn)行:程序沒(méi)啟動(dòng)。

  • Inactive未激活:程序在前臺(tái)運(yùn)行,不過(guò)沒(méi)有接收到事件。在沒(méi)有事件處理情況下程序通常停留在這個(gè)狀態(tài)。

  • Active激活:程序在前臺(tái)運(yùn)行而且接收到了事件。這也是前臺(tái)的一個(gè)正常的模式。

  • Backgroud后臺(tái):程序在后臺(tái)而且能執(zhí)行代碼,大多數(shù)程序進(jìn)入這個(gè)狀態(tài)后會(huì)在在這個(gè)狀態(tài)上停留一會(huì)。時(shí)間到之后會(huì)進(jìn)入掛起狀態(tài)(Suspended)。有的程序經(jīng)過(guò)特殊的請(qǐng)求后可以長(zhǎng)期處于Backgroud狀態(tài)。

  • Suspended掛起:程序在后臺(tái)不能執(zhí)行代碼。系統(tǒng)會(huì)自動(dòng)把程序變成這個(gè)狀態(tài)而且不會(huì)發(fā)出通知。當(dāng)掛起時(shí),程序還是停留在內(nèi)存中的,當(dāng)系統(tǒng)內(nèi)存低時(shí),系統(tǒng)就把掛起的程序清除掉,為前臺(tái)程序提供更多的內(nèi)存。

iOS的入口在main.m文件

int main(int argc, char *argv[])
{
      @autoreleasepool {
                 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
      }
 }

main函數(shù)的兩個(gè)參數(shù),iOS中沒(méi)有用到,包括這兩個(gè)參數(shù)是為了與標(biāo)準(zhǔn)ANSI C保持一致。 UIApplicationMain函數(shù),前兩個(gè)和main函數(shù)一樣,重點(diǎn)是后兩個(gè)。

后兩個(gè)參數(shù)分別表示程序的主要類(principal class)和代理類(delegate class)。如果主要類(principal class)為nil,將從Info.plist中獲取,如果Info.plist中不存在對(duì)應(yīng)的key,則默認(rèn)為UIApplication;如果代理類(delegate class)將在新建工程時(shí)創(chuàng)建。

根據(jù)UIApplicationMain函數(shù),程序?qū)⑦M(jìn)入AppDelegate.m,這個(gè)文件是xcode新建工程時(shí)自動(dòng)生成的。下面看一下AppDelegate.m文件,這個(gè)關(guān)乎著應(yīng)用程序的生命周期。

1、application didFinishLaunchingWithOptions:當(dāng)應(yīng)用程序啟動(dòng)時(shí)執(zhí)行,應(yīng)用程序啟動(dòng)入口,只在應(yīng)用程序啟動(dòng)時(shí)執(zhí)行一次。若用戶直接啟動(dòng),lauchOptions內(nèi)無(wú)數(shù)據(jù),若通過(guò)其他方式啟動(dòng)應(yīng)用,lauchOptions包含對(duì)應(yīng)方式的內(nèi)容。

2、applicationWillResignActive:在應(yīng)用程序?qū)⒁苫顒?dòng)狀態(tài)切換到非活動(dòng)狀態(tài)時(shí)候,要執(zhí)行的委托調(diào)用,如 按下 home 按鈕,返回主屏幕,或全屏之間切換應(yīng)用程序等。

3、applicationDidEnterBackground:在應(yīng)用程序已進(jìn)入后臺(tái)程序時(shí),要執(zhí)行的委托調(diào)用。

4、applicationWillEnterForeground:在應(yīng)用程序?qū)⒁M(jìn)入前臺(tái)時(shí)(被激活),要執(zhí)行的委托調(diào)用,剛好與applicationWillResignActive 方法相對(duì)應(yīng)。

5、applicationDidBecomeActive:在應(yīng)用程序已被激活后,要執(zhí)行的委托調(diào)用,剛好與applicationDidEnterBackground 方法相對(duì)應(yīng)。

6、applicationWillTerminate:在應(yīng)用程序要完全推出的時(shí)候,要執(zhí)行的委托調(diào)用,這個(gè)需要要設(shè)置UIApplicationExitsOnSuspend的鍵值。

初次啟動(dòng):

iOS_didFinishLaunchingWithOptions
iOS_applicationDidBecomeActive

按下home鍵:

iOS_applicationWillResignActive
iOS_applicationDidEnterBackground

點(diǎn)擊程序圖標(biāo)進(jìn)入:

iOS_applicationWillEnterForeground
iOS_applicationDidBecomeActive

當(dāng)應(yīng)用程序進(jìn)入后臺(tái)時(shí),應(yīng)該保存用戶數(shù)據(jù)或狀態(tài)信息,所有沒(méi)寫到磁盤的文件或信息,在進(jìn)入后臺(tái)時(shí),最后都寫到磁盤去,因?yàn)槌绦蚩赡茉诤笈_(tái)被殺死。釋放盡可能釋放的內(nèi)存。

 - (void)applicationDidEnterBackground:(UIApplication *)application{
 }

方法有大概5秒的時(shí)間讓你完成這些任務(wù)。如果超過(guò)時(shí)間還有未完成的任務(wù),你的程序就會(huì)被終止而且從內(nèi)存中清除。

如果還需要長(zhǎng)時(shí)間的運(yùn)行任務(wù),可以在該方法中調(diào)用:

[application beginBackgroundTaskWithExpirationHandler:^{ 
      NSLog(@"begin Background Task With Expiration Handler"); 
 }];

程序終止

程序只要符合以下情況之一,只要進(jìn)入后臺(tái)或掛起狀態(tài)就會(huì)終止:

①iOS 4.0以前的系統(tǒng)

②app是基于iOS 4.0之前系統(tǒng)開發(fā)的。

③設(shè)備不支持多任務(wù)

④在Info.plist文件中,程序包含了 UIApplicationExitsOnSuspend 鍵。

系統(tǒng)常常是為其他app啟動(dòng)時(shí)由于內(nèi)存不足而回收內(nèi)存最后需要終止應(yīng)用程序,但有時(shí)也會(huì)是由于app很長(zhǎng)時(shí)間才響應(yīng)而終止。如果app當(dāng)時(shí)運(yùn)行在后臺(tái)并且沒(méi)有暫停,系統(tǒng)會(huì)在應(yīng)用程序終止之前調(diào)用app的代理的方法 - (void)applicationWillTerminate:(UIApplication *)application,這樣可以讓你可以做一些清理工作。你可以保存一些數(shù)據(jù)或app的狀態(tài)。這個(gè)方法也有5秒鐘的限制。超時(shí)后方法會(huì)返回程序從內(nèi)存中清除。

注意:用戶可以手工關(guān)閉應(yīng)用程序

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,860評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,025評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,421評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,642評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,177評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,970評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,157評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,410評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,896評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,157評(píng)論 2 375

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