SDWebImage源碼學(xué)習(xí)-One

源碼地址< https://github.com/rs/SDWebImage >
SDWebImage提供UIImageView的category叠必,支持從遠(yuǎn)程服務(wù)器下載及緩存圖片資源

SDWebImage功能:

  • UIImageView的category增加了Web圖片下載緩存操作
  • 一個(gè)異步的圖片加載器
  • 一個(gè)異步的內(nèi)存+磁盤(pán)緩存策略
  • GIF圖片支持
  • 支持WebP格式的圖片
  • 后臺(tái)圖片解壓縮處理
  • 確保同一個(gè)URL地址不會(huì)被重復(fù)下載
  • 確保一個(gè)假冒的URL地址不會(huì)被重復(fù)的請(qǐng)求
  • 確保主線(xiàn)程不會(huì)被阻塞
  • 使用GCD和ARC
  • Arm64的支持

SDWebImageManager

可以通過(guò)SDWebImageManager去下載緩存圖片谢谦,它將一個(gè)下載器(SDWebImageDownloader)和一個(gè)圖片緩存器(SDImageCache)綁定在一起醉蚁。經(jīng)常會(huì)使用到的分類(lèi)UIImageView+WebCache也是基于它實(shí)現(xiàn)的馒铃。下面是一個(gè)官方示例:

SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL
             options:0
            progress:nil
           completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
               if (image) {
                   // do something with image
               }
           }];

SDWebImageManager綁定的下載器和圖片緩存器都是只讀性質(zhì)开伏,先看看在SDWebImageManager.h文件里面的定義是如何

@interface SDWebImageManager : NSObject

@property (weak, nonatomic) id <SDWebImageManagerDelegate> delegate;

@property (strong, nonatomic, readonly) SDImageCache *imageCache;
@property (strong, nonatomic, readonly) SDWebImageDownloader *imageDownloader;

首先有一個(gè)delegate坏挠,其聲明了兩個(gè)可選的方法

//選擇控制哪個(gè)image該被下載奈懒,當(dāng)發(fā)現(xiàn)image不在cache中的時(shí)候
- (BOOL)imageManager:(SDWebImageManager *)imageManager shouldDownloadImageForURL:(NSURL *)imageURL;
//允許對(duì)圖片下載完后并且在存入緩存和磁盤(pán)前進(jìn)行轉(zhuǎn)換
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;

接下來(lái)看看SDWebImageManager主要下載圖片的方法奠涌,返回值是一個(gè)遵循SDWebImageOperation協(xié)議類(lèi)型的值

- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                                     options:(SDWebImageOptions)options
                                    progress:(SDWebImageDownloaderProgressBlock)progressBlock
                              completed:(SDWebImageCompletionWithFinishedBlock)completedBlock;

progressBlock在圖片正在下載的時(shí)候進(jìn)行處理,completedBlock當(dāng)圖片下載完成后進(jìn)行的處理。上面已經(jīng)有個(gè)小例子,下面是block的聲明

typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);//聲明在SDWebImageDownloader.h文件中

typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL);

剩余的方法可以一并看看

- (void)saveImageToCache:(UIImage *)image forURL:(NSURL *)url;//保存圖片到cache
- (void)cancelAll;//取消所有操作
- (BOOL)isRunning;//檢查是否有下載圖片操作在運(yùn)行
- (BOOL)cachedImageExistsForURL:(NSURL *)url;//檢查圖片是否在cache中
- (BOOL)diskImageExistsForURL:(NSURL *)url;//檢查圖片是否在磁盤(pán)中
//檢查圖片是否在cache中磷杏,檢查結(jié)束后進(jìn)行block操作
- (void)cachedImageExistsForURL:(NSURL *)url
                 completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
//檢查圖片是否在磁盤(pán)中溜畅,檢查結(jié)束后進(jìn)行block操作
- (void)diskImageExistsForURL:(NSURL *)url
               completion:(SDWebImageCheckCacheCompletionBlock)completionBlock;
- (NSString *)cacheKeyForURL:(NSURL *)url;//根據(jù)url返回cache的key值

看完SDWebImageManager.h文件再看看SDWebImageManager.m文件里面一個(gè)遵循SDWebImageOperation協(xié)議的類(lèi)SDWebImageCombinedOperation。

@interface SDWebImageCombinedOperation : NSObject <SDWebImageOperation>
//是否已經(jīng)取消
@property (assign, nonatomic, getter = isCancelled) BOOL cancelled;
@property (copy, nonatomic) SDWebImageNoParamsBlock cancelBlock;
//真正用來(lái)控制下載的operation
@property (strong, nonatomic) NSOperation *cacheOperation;

@end

SDWebImageManager.m里面的大部分操作都是在下載圖片的環(huán)節(jié)极祸,通過(guò)SDImageCache和SDWebImageDownloader來(lái)實(shí)現(xiàn)慈格。其它一些判斷存在性的操作也很容易理解。

typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
//默認(rèn)情況下遥金,當(dāng)URL下載失敗浴捆,該URL會(huì)被列入黑名單,庫(kù)就不會(huì)再去嘗試獲取該URL稿械,該標(biāo)記用來(lái)禁用黑名單
    SDWebImageRetryFailed = 1 << 0,
//默認(rèn)情況下选泻,圖片下載是在UI交互的時(shí)候,該標(biāo)記用來(lái)禁用這個(gè)情況美莫,這樣子下載會(huì)延遲到UIScrollView減速的時(shí)候
    SDWebImageLowPriority = 1 << 1,
//該標(biāo)記禁用磁盤(pán)緩存
    SDWebImageCacheMemoryOnly = 1 << 2,
//該標(biāo)記用來(lái)漸進(jìn)式下載页眯,如果瀏覽器一樣,圖片在下載過(guò)程中漸漸顯示厢呵。默認(rèn)情況下是下載完一次性顯示
    SDWebImageProgressiveDownload = 1 << 3,
//即使圖片已經(jīng)緩存窝撵,也期望進(jìn)行HTTP響應(yīng)cache control并且如果有需要的話(huà)從遠(yuǎn)程地址更新圖片數(shù)據(jù)
//磁盤(pán)緩存將被NSURLCache處理而不是SDWebImage,因?yàn)镾DWebImage會(huì)導(dǎo)致輕微的性能下載襟铭。
//該標(biāo)記幫助處理在請(qǐng)求同樣的URL后面改變的圖片碌奉。如果緩存圖片被刷新短曾,則完成的block會(huì)使用緩存圖片再調(diào)用一次
    SDWebImageRefreshCached = 1 << 4,
//IOS4+,程序進(jìn)入后臺(tái)后仍然進(jìn)行下載圖片道批,請(qǐng)求系統(tǒng)給予額外的時(shí)間進(jìn)行下載错英,如果請(qǐng)求超時(shí)了,操作就會(huì)被取消
    SDWebImageContinueInBackground = 1 << 5,
//通過(guò)設(shè)定NSMutableURLRequest.HTTPShouldHandleCookies = YES;來(lái)處理存儲(chǔ)在NSHTTPCookieStore的cookies
    SDWebImageHandleCookies = 1 << 6,
//該標(biāo)記允許不受信任的SSL認(rèn)證
    SDWebImageAllowInvalidSSLCertificates = 1 << 7,
//默認(rèn)情況下是按入隊(duì)順序下載隆豹,該標(biāo)記可以讓其優(yōu)先下載
    SDWebImageHighPriority = 1 << 8
//默認(rèn)情況下椭岩,占位圖片在圖片被加載時(shí)同時(shí)被加載,這個(gè)標(biāo)記會(huì)讓占位圖片在圖片加載完后再加載
    SDWebImageDelayPlaceholder = 1 << 9,
// 我們通常不調(diào)用動(dòng)畫(huà)圖片的transformDownloadedImage代理方法璃赡,因?yàn)榇蠖鄶?shù)轉(zhuǎn)換代碼可以使它變得糟糕判哥。
// 使用這個(gè)標(biāo)記則在任何情況下都進(jìn)行轉(zhuǎn)換。
 SDWebImageTransformAnimatedImage = 1 << 10,
};

SDImageCache

SD的緩存機(jī)制碉考。首先來(lái)看看SDImageCache.h里面的一些聲明塌计。

//定義Cache類(lèi)型
typedef NS_ENUM(NSInteger, SDImageCacheType) {
//不使用cache獲得圖片,依然會(huì)從web下載圖片
    SDImageCacheTypeNone,
//圖片從disk獲得
    SDImageCacheTypeDisk,
//圖片從Memory中獲得  
    SDImageCacheTypeMemory
};

接下來(lái)是一些變量的聲明

//這個(gè)變量默認(rèn)值為YES,顯示比較高質(zhì)量的圖片侯谁,但是會(huì)浪費(fèi)比較多的內(nèi)存锌仅,可以通過(guò)設(shè)置NO來(lái)緩解內(nèi)存
@property (assign, nonatomic) BOOL shouldDecompressImages;
//總共的內(nèi)存允許圖片的消耗值
@property (assign, nonatomic) NSUInteger maxMemoryCost;
//圖片存活于內(nèi)存的時(shí)間初始化的時(shí)候默認(rèn)為一周
@property (assign, nonatomic) NSInteger maxCacheAge;
//每次存儲(chǔ)圖片大小的限制
@property (assign, nonatomic) NSUInteger maxCacheSize;

看看SDImageCache的初始化

- (id)initWithNamespace:(NSString *)ns {
if ((self = [super init])) {
    NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns];

    // 初始化 PNG 的數(shù)據(jù)簽名
    kPNGSignatureData = [NSData dataWithBytes:kPNGSignatureBytes length:8];

    // 創(chuàng)建IO隊(duì)列
    _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);

    //初始化清除緩存期限,默認(rèn)一周
    _maxCacheAge = kDefaultCacheMaxCacheAge;

    // 初始化緩沖器
    _memCache = [[NSCache alloc] init];
    _memCache.name = fullNamespace;

    // 初始化磁盤(pán)緩存
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    _diskCachePath = [paths[0] stringByAppendingPathComponent:fullNamespace];

    // 設(shè)置顯示高質(zhì)量圖片
    _shouldDecompressImages = YES;

    dispatch_sync(_ioQueue, ^{
        _fileManager = [NSFileManager new];
    });

#if TARGET_OS_IPHONE
    // 訂閱通知事件
//內(nèi)存不足的時(shí)候清除緩存
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(clearMemory)
                                                 name:UIApplicationDidReceiveMemoryWarningNotification
                                               object:nil];
//期限到的時(shí)候清除緩存
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(cleanDisk)
                                                 name:UIApplicationWillTerminateNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(backgroundCleanDisk)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
#endif
}
return self;}

SDImageCache中用來(lái)存儲(chǔ)圖片的方法:

- (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk {
    if (!image || !key) {
       return;
    }
//cost的值與maxCacheSize相關(guān)墙贱,如果大于這個(gè)值热芹,則在緩存不足時(shí)會(huì)被清除
 [self.memCache setObject:image forKey:key cost:image.size.height * image.size.width * image.scale * image.scale];
  if (toDisk) {//圖片是否存儲(chǔ)到disk中
       dispatch_async(self.ioQueue, ^{
           NSData *data = imageData;
         if (image && (recalculate || !data)) {
#if TARGET_OS_IPHONE
             BOOL imageIsPng = YES;
             if ([imageData length] >= [kPNGSignatureData length]) {
                   imageIsPng = ImageDataHasPNGPreffix(imageData);
              }
    //根據(jù)圖片格式,獲取data數(shù)據(jù)
                if (imageIsPng) {
                    data = UIImagePNGRepresentation(image);
                }
                else {
                    data = UIImageJPEGRepresentation(image, (CGFloat)1.0);
            }
#else
                data = [NSBitmapImageRep representationOfImageRepsInArray:image.representations usingType: NSJPEGFileType properties:nil];
#endif
        }
            if (data) {
                if (![_fileManager fileExistsAtPath:_diskCachePath]) {
                    [_fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL];              
                  }
        //存儲(chǔ)路徑和數(shù)據(jù)
             [_fileManager createFileAtPath:[self defaultCachePathForKey:key] contents:data attributes:nil];
        }
    });
}
}

幾個(gè)獲取緩存和清除緩存接口

- (NSUInteger)getSize //獲取磁盤(pán)緩存大小
- (NSUInteger)getDiskCount //獲取緩存圖片數(shù)量
- (void)clearMemory;//清除內(nèi)存
- (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion;//清除緩存惨撇,不管到期與否伊脓,完成后操作
- (void)clearDisk;//清除緩存,不管到期與否
- (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock;//清除到期緩存圖片魁衙,完成后操作
- (void)cleanDisk;//清除到期緩存圖片

來(lái)個(gè)示例代碼實(shí)現(xiàn)

SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager.imageCache setMaxMemoryCost:1000000];//設(shè)置總緩存大小报腔,默認(rèn)為0沒(méi)有限制
[manager.imageCache setMaxCacheSize:640000];//設(shè)置單個(gè)圖片限制大小
[manager.imageDownloader setMaxConcurrentDownloads:1];//設(shè)置同時(shí)下載線(xiàn)程數(shù),這是下載器的內(nèi)容剖淀,下面將會(huì)介紹
[manager downloadImageWithURL:[NSURL URLWithString:@"http://p9.qhimg.com/t01eb74a44c2eb43193.jpg"]
                      options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                          NSLog(@"%lu", receivedSize);
                      } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                          self.imageView1.image = image;
                          
                      }];
[manager downloadImageWithURL:[NSURL URLWithString:@"http://img.article.pchome.net/00/28/33/87/pic_lib/wm/kuanpin12.jpg"]
                      options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) {
                          NSLog(@"%lu", receivedSize);
                      } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                          self.imageView2.image = image;
                          
                      }];
NSUInteger size = [manager.imageCache getSize];
NSUInteger count = [manager.imageCache getDiskCount];
NSLog(@"size = %lu", size); // 644621(兩張測(cè)試圖片)
NSLog(@"count = %lu", count); // 2
[manager.imageCache clearDisk];
size = [manager.imageCache getSize];
count = [manager.imageCache getDiskCount];
NSLog(@"sizeClean = %lu", size);  //  0
NSLog(@"countClean = %lu", count);     //  0   這里使用的是clear

SDImageCache中有根據(jù)鍵值對(duì)清除的方法

- (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion;

還有一些根據(jù)key查詢(xún)圖片的方法

- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock;
- (UIImage *)imageFromMemoryCacheForKey:(NSString *)key;
- (UIImage *)imageFromDiskCacheForKey:(NSString *)key;

SDWebImageDownloader

SDWebImageDownloader.h里面的一些定義

//隊(duì)列的下載方式
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
    SDWebImageDownloaderFIFOExecutionOrder,//先進(jìn)先出
    SDWebImageDownloaderLIFOExecutionOrder//后進(jìn)先出
};

@property (assign, nonatomic) BOOL shouldDecompressImages;//與cache相同
@property (assign, nonatomic) NSInteger maxConcurrentDownloads;//最大下載線(xiàn)程數(shù)
@property (readonly, nonatomic) NSUInteger currentDownloadCount;//當(dāng)前下載線(xiàn)程數(shù)
@property (assign, nonatomic) NSTimeInterval downloadTimeout;//下載時(shí)間限制
@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder;//下載方式纯蛾,即FIFO、LIFO纵隔。
//下載圖片的方法
- (id <SDWebImageOperation>)downloadImageWithURL:(NSURL *)url
                                     options:(SDWebImageDownloaderOptions)options
                                    progress:(SDWebImageDownloaderProgressBlock)progressBlock
                                   completed:(SDWebImageDownloaderCompletedBlock)completedBlock;

其中有兩個(gè)Block,SD對(duì)于它們的聲明如下

//對(duì)于下載進(jìn)度進(jìn)行反饋
typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize);
//完成后對(duì)圖片和數(shù)據(jù)進(jìn)行處理茅撞,如果出錯(cuò),則進(jìn)行出錯(cuò)處理
typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished);

SDWebImageDownloader中巨朦,用到了NSOperationQueue來(lái)作為操作隊(duì)列米丘,因此NSOperationQueue所有操作適用于SDWebImage。

SDWebImageDownloaderOperation

SDWebImageDownloaderOperation中實(shí)現(xiàn)NSURLConnectionDataDelegate協(xié)議來(lái)實(shí)現(xiàn)數(shù)據(jù)的下載,主要通過(guò)三個(gè)方法

//連接成功
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
//接收數(shù)據(jù)糊啡,.m文件中實(shí)現(xiàn)反饋給SDWebImageDownloaderProgressBlock數(shù)據(jù)長(zhǎng)度
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
//下載結(jié)束后拄查,將結(jié)果反饋給SDWebImageDownloaderCompletedBlock
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection

暫時(shí)先寫(xiě)到這邊,剩下的源碼后續(xù)會(huì)繼續(xù)總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棚蓄,一起剝皮案震驚了整個(gè)濱河市堕扶,隨后出現(xiàn)的幾起案子碍脏,更是在濱河造成了極大的恐慌,老刑警劉巖稍算,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典尾,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡糊探,警方通過(guò)查閱死者的電腦和手機(jī)钾埂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)科平,“玉大人褥紫,你說(shuō)我怎么就攤上這事〉苫郏” “怎么了髓考?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)弃酌。 經(jīng)常有香客問(wèn)我氨菇,道長(zhǎng),這世上最難降的妖魔是什么妓湘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任查蓉,我火速辦了婚禮,結(jié)果婚禮上多柑,老公的妹妹穿的比我還像新娘。我一直安慰自己楣责,他們只是感情好竣灌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著秆麸,像睡著了一般初嘹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沮趣,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天屯烦,我揣著相機(jī)與錄音,去河邊找鬼房铭。 笑死驻龟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缸匪。 我是一名探鬼主播翁狐,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凌蔬!你這毒婦竟也來(lái)了露懒?” 一聲冷哼從身側(cè)響起闯冷,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎懈词,沒(méi)想到半個(gè)月后蛇耀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坎弯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年纺涤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荞怒。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洒琢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出褐桌,到底是詐尸還是另有隱情衰抑,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布荧嵌,位于F島的核電站呛踊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏啦撮。R本人自食惡果不足惜谭网,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赃春。 院中可真熱鬧愉择,春花似錦、人聲如沸织中。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狭吼。三九已至层坠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刁笙,已是汗流浹背破花。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疲吸,地道東北人座每。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像摘悴,于是被迫代替她去往敵國(guó)和親尺栖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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