AFNetworking源碼探究(二十一) —— UIKit相關(guān)之UIImageView+AFNetworking分類(四)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.03.05

前言

我們做APP發(fā)起網(wǎng)絡(luò)請(qǐng)求,都離不開一個(gè)非常有用的框架AFNetworking腥例,可以說這個(gè)框架的知名度已經(jīng)超過了蘋果的底層網(wǎng)絡(luò)請(qǐng)求部分,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請(qǐng)求的,但是一定知道AFNetworking铐炫,接下來幾篇我們就一起詳細(xì)的解析一下這個(gè)框架黎烈。感興趣的可以看上面寫的幾篇习柠。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請(qǐng)求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)
3. AFNetworking源碼探究(三) —— GET請(qǐng)求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(一)
4. AFNetworking源碼探究(四) —— GET請(qǐng)求實(shí)現(xiàn)之代理轉(zhuǎn)發(fā)思想(一)
5. AFNetworking源碼探究(五) —— AFURLSessionManager中NSURLSessionDelegate詳細(xì)解析(一)
6. AFNetworking源碼探究(六) —— AFURLSessionManager中NSURLSessionTaskDelegate詳細(xì)解析(一)
7. AFNetworking源碼探究(七) —— AFURLSessionManager中NSURLSessionDataDelegate詳細(xì)解析(一)
8. AFNetworking源碼探究(八) —— AFURLSessionManager中NSURLSessionDownloadDelegate詳細(xì)解析(一)
9. AFNetworking源碼探究(九) —— AFURLSessionManagerTaskDelegate中三個(gè)轉(zhuǎn)發(fā)代理方法詳細(xì)解析(一)
10. AFNetworking源碼探究(十) —— 數(shù)據(jù)解析之?dāng)?shù)據(jù)解析架構(gòu)的分析(一)
11. AFNetworking源碼探究(十一) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(二)
12. AFNetworking源碼探究(十二) —— 數(shù)據(jù)解析之子類中協(xié)議方法的實(shí)現(xiàn)(三)
13. AFNetworking源碼探究(十三) —— AFSecurityPolicy與安全認(rèn)證 (一)
14. AFNetworking源碼探究(十四) —— AFSecurityPolicy與安全認(rèn)證 (二)
15. AFNetworking源碼探究(十五) —— 請(qǐng)求序列化之架構(gòu)分析(一)
16. AFNetworking源碼探究(十六) —— 請(qǐng)求序列化之協(xié)議方法的實(shí)現(xiàn)(二)
17. AFNetworking源碼探究(十七) —— _AFURLSessionTaskSwizzling實(shí)現(xiàn)方法交換(轉(zhuǎn)載)(一)
18. AFNetworking源碼探究(十八) —— UIKit相關(guān)之AFNetworkActivityIndicatorManager(一)
19. AFNetworking源碼探究(十九) —— UIKit相關(guān)之幾個(gè)分類(二)
20. AFNetworking源碼探究(二十) —— UIKit相關(guān)之AFImageDownloader圖像下載(三)

回顧

上一篇是關(guān)于AFImageDownloader圖像下載的內(nèi)容,這一篇主要是關(guān)于UIImageView的分類AFNetworking照棋。


AFNetworking類

先看一下UIImageView的分類AFNetworking的接口资溃。

#import <Foundation/Foundation.h>

#import <TargetConditionals.h>

#if TARGET_OS_IOS || TARGET_OS_TV

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@class AFImageDownloader;

/**
 This category adds methods to the UIKit framework's `UIImageView` class. The methods in this category provide support for loading remote images asynchronously from a URL.
 */
// 此類為UIKit框架的UIImageView類添加方法。 此類別中的方法支持從URL異步加載遠(yuǎn)程圖像烈炭。
@interface UIImageView (AFNetworking)

///------------------------------------
/// @name Accessing the Image Downloader
///------------------------------------

/**
 Set the shared image downloader used to download images.

 @param imageDownloader The shared image downloader used to download images.
 */
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader;

/**
 The shared image downloader used to download images.
 */
+ (AFImageDownloader *)sharedImageDownloader;

///--------------------
/// @name Setting Image
///--------------------

/**
 Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled.

 If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

 By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`

 @param url The URL used for the image request.
 */
// 異步地從指定的URL下載圖像溶锭,并在請(qǐng)求完成后進(jìn)行設(shè)置。 
// 以前任何接收者的圖像請(qǐng)求都將被取消梳庆。

// 如果圖像在本地緩存暖途,則立即設(shè)置圖像卑惜,否則將立即設(shè)置指定的占位符圖像,
// 然后在請(qǐng)求完成后設(shè)置遠(yuǎn)程圖像驻售。

// 默認(rèn)情況下露久,URL請(qǐng)求的“Accept”標(biāo)頭字段值為“image / *”,緩存策略為“NSURLCacheStorageAllowed”欺栗,
// 超時(shí)間隔為30秒毫痕,并且設(shè)置為不處理cookie。 要以不同的方式配置URL請(qǐng)求迟几,
// 請(qǐng)使用`setImageWithURLRequest:placeholderImage:success:failure:`
- (void)setImageWithURL:(NSURL *)url;

/**
 Asynchronously downloads an image from the specified URL, and sets it once the request is finished. Any previous image request for the receiver will be cancelled.

 If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

 By default, URL requests have a `Accept` header field value of "image / *", a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:`

 @param url The URL used for the image request.
 @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
 */
- (void)setImageWithURL:(NSURL *)url
       placeholderImage:(nullable UIImage *)placeholderImage;

/**
 Asynchronously downloads an image from the specified URL request, and sets it once the request is finished. Any previous image request for the receiver will be cancelled.

 If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished.

 If a success block is specified, it is the responsibility of the block to set the image of the image view before returning. If no success block is specified, the default behavior of setting the image with `self.image = image` is applied.

 @param urlRequest The URL request used for the image request.
 @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
 @param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
 @param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
 */
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
              placeholderImage:(nullable UIImage *)placeholderImage
                       success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                       failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;

/**
 Cancels any executing image operation for the receiver, if one exists.
 */
- (void)cancelImageDownloadTask;

@end

NS_ASSUME_NONNULL_END

#endif

怎么樣消请,大家有沒有很熟悉,沒錯(cuò)类腮,這個(gè)和SDWebImage非常類似臊泰,包括接口的調(diào)用和實(shí)現(xiàn)。


runtime綁定

這里采用runtime進(jìn)行綁定獲取分類的對(duì)象蚜枢。

+ (AFImageDownloader *)sharedImageDownloader {
    return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
}

+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
    objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

然后調(diào)用AFImageDownloader獲取下載器的實(shí)例化對(duì)象缸逃。


下載接口的調(diào)用

下面看一下下載圖像的接口調(diào)用。

- (void)setImageWithURL:(NSURL *)url;
- (void)setImageWithURL:(NSURL *)url
       placeholderImage:(nullable UIImage *)placeholderImage;
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
              placeholderImage:(nullable UIImage *)placeholderImage
                       success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                       failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;

這個(gè)接口和SDWebImage非常類似厂抽,實(shí)現(xiàn)也差不多這樣需频。


下載接口的實(shí)現(xiàn)

下面就看一下下載接口的實(shí)現(xiàn)。

- (void)setImageWithURL:(NSURL *)url {
    [self setImageWithURL:url placeholderImage:nil];
}

- (void)setImageWithURL:(NSURL *)url
       placeholderImage:(UIImage *)placeholderImage
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request addValue:@"image/*" forHTTPHeaderField:@"Accept"];

    [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil];
}

- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
              placeholderImage:(UIImage *)placeholderImage
                       success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
                       failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{

    if ([urlRequest URL] == nil) {
        [self cancelImageDownloadTask];
        self.image = placeholderImage;
        return;
    }

    if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
        return;
    }

    [self cancelImageDownloadTask];

    AFImageDownloader *downloader = [[self class] sharedImageDownloader];
    id <AFImageRequestCache> imageCache = downloader.imageCache;

    //Use the image from the image cache if it exists
    UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
    if (cachedImage) {
        if (success) {
            success(urlRequest, nil, cachedImage);
        } else {
            self.image = cachedImage;
        }
        [self clearActiveDownloadInformation];
    } else {
        if (placeholderImage) {
            self.image = placeholderImage;
        }

        __weak __typeof(self)weakSelf = self;
        NSUUID *downloadID = [NSUUID UUID];
        AFImageDownloadReceipt *receipt;
        receipt = [downloader
                   downloadImageForURLRequest:urlRequest
                   withReceiptID:downloadID
                   success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                       if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                           if (success) {
                               success(request, response, responseObject);
                           } else if(responseObject) {
                               strongSelf.image = responseObject;
                           }
                           [strongSelf clearActiveDownloadInformation];
                       }

                   }
                   failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                       __strong __typeof(weakSelf)strongSelf = weakSelf;
                        if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                            if (failure) {
                                failure(request, response, error);
                            }
                            [strongSelf clearActiveDownloadInformation];
                        }
                   }];

        self.af_activeImageDownloadReceipt = receipt;
    }
}

這個(gè)類主要做下面幾個(gè)工作:

1. 容錯(cuò)處理

if ([urlRequest URL] == nil) {
    [self cancelImageDownloadTask];
    self.image = placeholderImage;
    return;
}

這里如果request的URL不存在的話筷凤,那就無法請(qǐng)求了昭殉,這里就將當(dāng)前UIImageView的image設(shè)置為palceHolder圖像,并取消該圖像下載任務(wù)藐守。

- (void)cancelImageDownloadTask {
    if (self.af_activeImageDownloadReceipt != nil) {
        [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:self.af_activeImageDownloadReceipt];
        [self clearActiveDownloadInformation];
     }
}

這里就是圖像下載任務(wù)取消的實(shí)現(xiàn):

  • 首先就是判斷下載任務(wù)的憑據(jù)是否存在挪丢,如果不存在不用管,說明沒有這個(gè)任務(wù)吗伤,這里只處理有這個(gè)任務(wù)的情況吃靠。
  • 調(diào)用下載器的cancelTaskForImageDownloadReceipt:方法,帶人憑據(jù)參數(shù)足淆,取消下載任務(wù)巢块。
  • 初始化憑據(jù)參數(shù),置為nil巧号,實(shí)現(xiàn)過程如下族奢。
- (void)clearActiveDownloadInformation {
    self.af_activeImageDownloadReceipt = nil;
}

2. 存在任務(wù)的判斷

下面就看一下根據(jù)URL判斷任務(wù)是否存在,如果存在就return丹鸿,接著就是取消圖像下載任務(wù)越走。

if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
    return;
}

[self cancelImageDownloadTask];
- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest {
    return [self.af_activeImageDownloadReceipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}

3. 獲取緩存圖像并做決策

首先看一下這段代碼

AFImageDownloader *downloader = [[self class] sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;

//Use the image from the image cache if it exists
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
if (cachedImage) {
    if (success) {
        success(urlRequest, nil, cachedImage);
    } else {
        self.image = cachedImage;
    }
    [self clearActiveDownloadInformation];
} else {
    if (placeholderImage) {
        self.image = placeholderImage;
    }

    __weak __typeof(self)weakSelf = self;
    NSUUID *downloadID = [NSUUID UUID];
    AFImageDownloadReceipt *receipt;
    receipt = [downloader
               downloadImageForURLRequest:urlRequest
               withReceiptID:downloadID
               success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
                   __strong __typeof(weakSelf)strongSelf = weakSelf;
                   if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                       if (success) {
                           success(request, response, responseObject);
                       } else if(responseObject) {
                           strongSelf.image = responseObject;
                       }
                       [strongSelf clearActiveDownloadInformation];
                   }

               }
               failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                   __strong __typeof(weakSelf)strongSelf = weakSelf;
                    if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                        if (failure) {
                            failure(request, response, error);
                        }
                        [strongSelf clearActiveDownloadInformation];
                    }
               }];

    self.af_activeImageDownloadReceipt = receipt;
}

這段代碼,主要完成下面幾個(gè)工作:

  • 獲取緩存圖像
  • 如果存在,就進(jìn)行回調(diào)和設(shè)置圖像
  • 不存在就開始下載圖像

(a) 獲取緩存圖像

我們首先看一下緩存圖像廊敌。

AFImageDownloader *downloader = [[self class] sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;

//Use the image from the image cache if it exists
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];

這里铜跑,首先是獲取下載器,然后獲取下載器的緩存骡澈,最后根據(jù)請(qǐng)求request獲取UIImage锅纺。

(b) 緩存圖像存在

主要對(duì)應(yīng)下面這段代碼

if (cachedImage) {
    if (success) {
        success(urlRequest, nil, cachedImage);
    } else {
        self.image = cachedImage;
    }
    [self clearActiveDownloadInformation];
} 

如果緩存圖像存在,如果success的block存在就回調(diào)出去肋殴,否則就賦值給image囤锉。最后還是調(diào)用clearActiveDownloadInformation,清除下載信息护锤。

(c) 緩存圖像不存在

其實(shí)主要對(duì)應(yīng)下面這段代碼

else {
    if (placeholderImage) {
        self.image = placeholderImage;
    }

    __weak __typeof(self)weakSelf = self;
    NSUUID *downloadID = [NSUUID UUID];
    AFImageDownloadReceipt *receipt;
    receipt = [downloader
               downloadImageForURLRequest:urlRequest
               withReceiptID:downloadID
               success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
                   __strong __typeof(weakSelf)strongSelf = weakSelf;
                   if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                       if (success) {
                           success(request, response, responseObject);
                       } else if(responseObject) {
                           strongSelf.image = responseObject;
                       }
                       [strongSelf clearActiveDownloadInformation];
                   }

               }
               failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
                   __strong __typeof(weakSelf)strongSelf = weakSelf;
                    if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
                        if (failure) {
                            failure(request, response, error);
                        }
                        [strongSelf clearActiveDownloadInformation];
                    }
               }];

    self.af_activeImageDownloadReceipt = receipt;
}

緩存圖像不存在官地,那就是要開始下載了。主要步驟如下:

  • 暫時(shí)將圖像設(shè)置為占位符烙懦。
  • 根據(jù)下載器返回的憑據(jù)驱入,更新內(nèi)存中的有效憑據(jù)self.af_activeImageDownloadReceipt
  • 用下載器進(jìn)行下載氯析,不管成功還是失敗都進(jìn)行相應(yīng)的回調(diào)沧侥,并清除下載信息clearActiveDownloadInformation。并在成功的時(shí)候設(shè)置圖像替換掉下載圖strongSelf.image = responseObject魄鸦。

后記

本篇講述了關(guān)于UIImageView的分類,用于下載圖像癣朗。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拾因,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子旷余,更是在濱河造成了極大的恐慌绢记,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件正卧,死亡現(xiàn)場離奇詭異蠢熄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)炉旷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門签孔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窘行,你說我怎么就攤上這事饥追。” “怎么了罐盔?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵但绕,是天一觀的道長。 經(jīng)常有香客問我,道長捏顺,這世上最難降的妖魔是什么六孵? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮幅骄,結(jié)果婚禮上劫窒,老公的妹妹穿的比我還像新娘。我一直安慰自己昌执,他們只是感情好烛亦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著懂拾,像睡著了一般煤禽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上岖赋,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天檬果,我揣著相機(jī)與錄音,去河邊找鬼唐断。 笑死选脊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脸甘。 我是一名探鬼主播恳啥,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丹诀!你這毒婦竟也來了钝的?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤铆遭,失蹤者是張志新(化名)和其女友劉穎硝桩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枚荣,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碗脊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了橄妆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衙伶。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖害碾,靈堂內(nèi)的尸體忽然破棺而出痕支,到底是詐尸還是另有隱情,我是刑警寧澤蛮原,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布卧须,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏花嘶。R本人自食惡果不足惜笋籽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望椭员。 院中可真熱鬧车海,春花似錦、人聲如沸隘击。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埋同。三九已至州叠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凶赁,已是汗流浹背咧栗。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虱肄,地道東北人致板。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像咏窿,于是被迫代替她去往敵國和親斟或。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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