AFNetworking源碼探究(二十六) —— UIKit相關(guān)之AFAutoPurgingImageCache緩存(九)

版本記錄

版本號 時(shí)間
V1.0 2018.03.06

前言

我們做APP發(fā)起網(wǎng)絡(luò)請求押搪,都離不開一個(gè)非常有用的框架AFNetworking,可以說這個(gè)框架的知名度已經(jīng)超過了蘋果的底層網(wǎng)絡(luò)請求部分艇劫,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請求的掉缺,但是一定知道AFNetworking炼鞠,接下來幾篇我們就一起詳細(xì)的解析一下這個(gè)框架。感興趣的可以看上面寫的幾篇券躁。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)
3. AFNetworking源碼探究(三) —— GET請求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(一)
4. AFNetworking源碼探究(四) —— GET請求實(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源碼探究(十五) —— 請求序列化之架構(gòu)分析(一)
16. AFNetworking源碼探究(十六) —— 請求序列化之協(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圖像下載(三)
21. AFNetworking源碼探究(二十一) —— UIKit相關(guān)之UIImageView+AFNetworking分類(四)
22. AFNetworking源碼探究(二十二) —— UIKit相關(guān)之UIButton+AFNetworking分類(五)
23. AFNetworking源碼探究(二十三) —— UIKit相關(guān)之UIWebView+AFNetworking分類(六)
24. AFNetworking源碼探究(二十四) —— UIKit相關(guān)之UIProgressView+AFNetworking分類(七)
25. AFNetworking源碼探究(二十五) —— UIKit相關(guān)之UIRefreshControl+AFNetworking分類(八)

回顧

上一篇主要講述了UIRefreshControl+AFNetworking這個(gè)分類惩坑,將刷新狀態(tài)和任務(wù)狀態(tài)進(jìn)行了綁定和同步。這一篇主要講述AFAutoPurgingImageCache有關(guān)的緩存也拜。


接口API

按照老慣例以舒,我們還是先看一下接口API文檔。這個(gè)接口文檔包括三個(gè)部分慢哈,兩個(gè)協(xié)議一個(gè)類蔓钟。

  • 協(xié)議AFImageCache
  • 協(xié)議AFImageRequestCache
  • AFAutoPurgingImageCache

1. AFImageCache

這個(gè)協(xié)議包括四個(gè)方法

/**
 Adds the image to the cache with the given identifier.

 @param image The image to cache.
 @param identifier The unique identifier for the image in the cache.
 */
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;

/**
 Removes the image from the cache matching the given identifier.

 @param identifier The unique identifier for the image in the cache.

 @return A BOOL indicating whether or not the image was removed from the cache.
 */
- (BOOL)removeImageWithIdentifier:(NSString *)identifier;

/**
 Removes all images from the cache.

 @return A BOOL indicating whether or not all images were removed from the cache.
 */
- (BOOL)removeAllImages;

/**
 Returns the image in the cache associated with the given identifier.

 @param identifier The unique identifier for the image in the cache.

 @return An image for the matching identifier, or nil.
 */
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;

該協(xié)議定義了包括加入、移除卵贱、獲取緩存中的圖片滥沫。

2. AFImageRequestCache

該協(xié)議包含下面幾個(gè)方法,這里注意這個(gè)協(xié)議繼承自協(xié)議AFImageCache艰赞。

@protocol AFImageRequestCache <AFImageCache>

/**
 Asks if the image should be cached using an identifier created from the request and additional identifier.
 
 @param image The image to be cached.
 @param request The unique URL request identifing the image asset.
 @param identifier The additional identifier to apply to the URL request to identify the image.
 
 @return A BOOL indicating whether or not the image should be added to the cache. YES will cache, NO will prevent caching.
 */
- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;

/**
 Adds the image to the cache using an identifier created from the request and additional identifier.

 @param image The image to cache.
 @param request The unique URL request identifing the image asset.
 @param identifier The additional identifier to apply to the URL request to identify the image.
 */
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;

/**
 Removes the image from the cache using an identifier created from the request and additional identifier.

 @param request The unique URL request identifing the image asset.
 @param identifier The additional identifier to apply to the URL request to identify the image.
 
 @return A BOOL indicating whether or not all images were removed from the cache.
 */
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;

/**
 Returns the image from the cache associated with an identifier created from the request and additional identifier.

 @param request The unique URL request identifing the image asset.
 @param identifier The additional identifier to apply to the URL request to identify the image.

 @return An image for the matching request and identifier, or nil.
 */
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;

@end

根據(jù)請求和標(biāo)識對圖像進(jìn)行是否需要緩存佣谐、加入到緩存或者移除緩存等進(jìn)行操作。

3. AFAutoPurgingImageCache

這個(gè)是這個(gè)類的接口方妖,大家注意下這個(gè)類遵循協(xié)議AFImageRequestCache狭魂。

/**
 The `AutoPurgingImageCache` in an in-memory image cache used to store images up to a given memory capacity. When the memory capacity is reached, the image cache is sorted by last access date, then the oldest image is continuously purged until the preferred memory usage after purge is met. Each time an image is accessed through the cache, the internal access date of the image is updated.
 */
@interface AFAutoPurgingImageCache : NSObject <AFImageRequestCache>

/**
 The total memory capacity of the cache in bytes.
 */
// 內(nèi)存緩存總的字節(jié)數(shù)
@property (nonatomic, assign) UInt64 memoryCapacity;

/**
 The preferred memory usage after purge in bytes. During a purge, images will be purged until the memory capacity drops below this limit.
 */
// 以字節(jié)為單位清除后的首選內(nèi)存使用情況。 在清除過程中党觅,圖像將被清除雌澄,直到內(nèi)存容量降至此限制以下。
@property (nonatomic, assign) UInt64 preferredMemoryUsageAfterPurge;

/**
 The current total memory usage in bytes of all images stored within the cache.
 */
// 當(dāng)前所有圖像內(nèi)存緩存使用的總的字節(jié)數(shù)
@property (nonatomic, assign, readonly) UInt64 memoryUsage;

/**
 Initialies the `AutoPurgingImageCache` instance with default values for memory capacity and preferred memory usage after purge limit. `memoryCapcity` defaults to `100 MB`. `preferredMemoryUsageAfterPurge` defaults to `60 MB`.
// 初始化杯瞻,memoryCapcity為100M镐牺,preferredMemoryUsageAfterPurge為60M

 @return The new `AutoPurgingImageCache` instance.
 */
- (instancetype)init;

/**
 Initialies the `AutoPurgingImageCache` instance with the given memory capacity and preferred memory usage
 after purge limit.

 @param memoryCapacity The total memory capacity of the cache in bytes.
 @param preferredMemoryCapacity The preferred memory usage after purge in bytes.

 @return The new `AutoPurgingImageCache` instance.
 */
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity;

@end

內(nèi)存中圖像緩存中的AutoPurgingImageCache用于存儲圖像到給定內(nèi)存容量。 達(dá)到內(nèi)存容量時(shí)魁莉,圖像緩存按上次訪問日期排序睬涧,然后最舊的圖像不斷清除,直到滿足清除后的首選內(nèi)存使用量旗唁。 每次通過緩存訪問圖像時(shí)畦浓,圖像的內(nèi)部訪問日期都會更新。


AFAutoPurgingImageCache接口及初始化

從接口描述中我們可以看出來检疫,類的初始化規(guī)定了內(nèi)存總的使用量以及清楚以后的內(nèi)存最優(yōu)大小讶请。

- (instancetype)init {
    return [self initWithMemoryCapacity:100 * 1024 * 1024 preferredMemoryCapacity:60 * 1024 * 1024];
}

- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity {
    if (self = [super init]) {
        self.memoryCapacity = memoryCapacity;
        self.preferredMemoryUsageAfterPurge = preferredMemoryCapacity;
        self.cachedImages = [[NSMutableDictionary alloc] init];

        NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
        self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);

        [[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(removeAllImages)
         name:UIApplicationDidReceiveMemoryWarningNotification
         object:nil];

    }
    return self;
}

我們看一下這個(gè)初始化方法中都做了什么事情

  • 設(shè)置緩存圖像的字典
self.cachedImages = [[NSMutableDictionary alloc] init];
  • 常見和UUID關(guān)聯(lián)的并發(fā)隊(duì)列
NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
  • 增加移除所有圖像的通知
[[NSNotificationCenter defaultCenter]
         addObserver:self
         selector:@selector(removeAllImages)
         name:UIApplicationDidReceiveMemoryWarningNotification
         object:nil];
- (BOOL)removeAllImages {
    __block BOOL removed = NO;
    dispatch_barrier_sync(self.synchronizationQueue, ^{
        if (self.cachedImages.count > 0) {
            [self.cachedImages removeAllObjects];
            self.currentMemoryUsage = 0;
            removed = YES;
        }
    });
    return removed;
}

這里就是在上面生成的隊(duì)列中,清空數(shù)組屎媳,重置一些屬性值夺溢。


AFCachedImage接口及初始化

這里我們就看一下AFCachedImage的接口及初始化论巍。

@interface AFCachedImage : NSObject

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, assign) UInt64 totalBytes;
@property (nonatomic, strong) NSDate *lastAccessDate;
@property (nonatomic, assign) UInt64 currentMemoryUsage;

@end

- (instancetype)initWithImage:(UIImage *)image identifier:(NSString *)identifier {
    if (self = [self init]) {
        self.image = image;
        self.identifier = identifier;

        CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale);
        CGFloat bytesPerPixel = 4.0;
        CGFloat bytesPerSize = imageSize.width * imageSize.height;
        self.totalBytes = (UInt64)bytesPerPixel * (UInt64)bytesPerSize;
        self.lastAccessDate = [NSDate date];
    }
    return self;
}

這個(gè)初始化方法里面初始化圖像的字節(jié)數(shù),并更新上次獲取數(shù)據(jù)的時(shí)間风响。


協(xié)議方法的實(shí)現(xiàn)

1. AFImageCache協(xié)議的實(shí)現(xiàn)

將圖像根據(jù)標(biāo)識添加到內(nèi)存

- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
    dispatch_barrier_async(self.synchronizationQueue, ^{
        AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];

        AFCachedImage *previousCachedImage = self.cachedImages[identifier];
        if (previousCachedImage != nil) {
            self.currentMemoryUsage -= previousCachedImage.totalBytes;
        }

        self.cachedImages[identifier] = cacheImage;
        self.currentMemoryUsage += cacheImage.totalBytes;
    });

    dispatch_barrier_async(self.synchronizationQueue, ^{
        if (self.currentMemoryUsage > self.memoryCapacity) {
            UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
            NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
            NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"
                                                                           ascending:YES];
            [sortedImages sortUsingDescriptors:@[sortDescriptor]];

            UInt64 bytesPurged = 0;

            for (AFCachedImage *cachedImage in sortedImages) {
                [self.cachedImages removeObjectForKey:cachedImage.identifier];
                bytesPurged += cachedImage.totalBytes;
                if (bytesPurged >= bytesToPurge) {
                    break ;
                }
            }
            self.currentMemoryUsage -= bytesPurged;
        }
    });
}

這里用到了兩個(gè)阻塞

  • 第一個(gè)阻塞
dispatch_barrier_async(self.synchronizationQueue, ^{
    AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];

    AFCachedImage *previousCachedImage = self.cachedImages[identifier];
    if (previousCachedImage != nil) {
        self.currentMemoryUsage -= previousCachedImage.totalBytes;
    }

    self.cachedImages[identifier] = cacheImage;
    self.currentMemoryUsage += cacheImage.totalBytes;
});

這里的作用其實(shí)很清楚嘉汰,就是先根據(jù)image和identify實(shí)例化AFCachedImage對象。然后在字典中根據(jù)identifier查看是否有AFCachedImage對象钞诡,如果有的話郑现,那么就減小當(dāng)前使用內(nèi)存的值。并將前面實(shí)例化的AFCachedImage對象存入字典中荧降,并增加當(dāng)前使用內(nèi)存的值接箫。

  • 第二個(gè)阻塞
dispatch_barrier_async(self.synchronizationQueue, ^{
    if (self.currentMemoryUsage > self.memoryCapacity) {
        UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
        NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"
                                                                       ascending:YES];
        [sortedImages sortUsingDescriptors:@[sortDescriptor]];

        UInt64 bytesPurged = 0;

        for (AFCachedImage *cachedImage in sortedImages) {
            [self.cachedImages removeObjectForKey:cachedImage.identifier];
            bytesPurged += cachedImage.totalBytes;
            if (bytesPurged >= bytesToPurge) {
                break ;
            }
        }
        self.currentMemoryUsage -= bytesPurged;
    }
});

這里完成的功能是,首先判斷如果當(dāng)前內(nèi)存使用量大于內(nèi)存總量朵诫,那么就需要清理了辛友,這里需要計(jì)算需要清理多少內(nèi)存,就是當(dāng)前內(nèi)存值 - 最優(yōu)內(nèi)存值剪返。然后sortedImages實(shí)例化字典中所有的圖片废累,并對這些圖片進(jìn)行按照時(shí)間的排序,遍歷這個(gè)排序后的數(shù)組脱盲,逐一從字典中移除邑滨,終止條件就是移除的字節(jié)數(shù)大于上面計(jì)算的要清除的字節(jié)數(shù)值。最后钱反,更新下當(dāng)前內(nèi)存使用的值掖看。

根據(jù)指定標(biāo)識將圖像移出內(nèi)存

- (BOOL)removeImageWithIdentifier:(NSString *)identifier;
- (BOOL)removeImageWithIdentifier:(NSString *)identifier {
    __block BOOL removed = NO;
    dispatch_barrier_sync(self.synchronizationQueue, ^{
        AFCachedImage *cachedImage = self.cachedImages[identifier];
        if (cachedImage != nil) {
            [self.cachedImages removeObjectForKey:identifier];
            self.currentMemoryUsage -= cachedImage.totalBytes;
            removed = YES;
        }
    });
    return removed;
}

這個(gè)還是很好理解的,在定義的并行隊(duì)列中面哥,取出identifier對應(yīng)的AFCachedImage對象哎壳,然后從字典中移除,并更新當(dāng)前內(nèi)存的值尚卫。

從內(nèi)存中移除所有的圖像

- (BOOL)removeAllImages;
- (BOOL)removeAllImages {
    __block BOOL removed = NO;
    dispatch_barrier_sync(self.synchronizationQueue, ^{
        if (self.cachedImages.count > 0) {
            [self.cachedImages removeAllObjects];
            self.currentMemoryUsage = 0;
            removed = YES;
        }
    });
    return removed;
}

其實(shí)就是一句話归榕,清空字典,更新當(dāng)前內(nèi)存使用值吱涉。

根據(jù)指定的標(biāo)識符從內(nèi)存中獲取圖像

- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;

- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
    __block UIImage *image = nil;
    dispatch_sync(self.synchronizationQueue, ^{
        AFCachedImage *cachedImage = self.cachedImages[identifier];
        image = [cachedImage accessImage];
    });
    return image;
}
- (UIImage*)accessImage {
    self.lastAccessDate = [NSDate date];
    return self.image;
}

其實(shí)就是從字典中取值刹泄,并更新上次獲取圖像的時(shí)間。

2. AFImageRequestCache協(xié)議的實(shí)現(xiàn)

根據(jù)請求和標(biāo)識符將圖像加入到內(nèi)存

- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
    [self addImage:image withIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}
- (NSString *)imageCacheKeyFromURLRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)additionalIdentifier {
    NSString *key = request.URL.absoluteString;
    if (additionalIdentifier != nil) {
        key = [key stringByAppendingString:additionalIdentifier];
    }
    return key;
}

這里其實(shí)是調(diào)用上面我們講過的那個(gè)根據(jù)identifier取出AFCachedImage對象的那個(gè)方法怎爵。不過下面這個(gè)identifier是通過調(diào)用下面這個(gè)方法生成的循签。

根據(jù)請求和標(biāo)識符將圖像移出內(nèi)存

- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
    return [self removeImageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}

這個(gè),就是還是利用那個(gè)生成indentifier的方法疙咸,獲取identify,然后調(diào)用前面我們講過的方法移除對應(yīng)的圖像风科。

根據(jù)請求和標(biāo)識符獲取內(nèi)存中圖像

- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
    return [self imageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}

這個(gè)撒轮,就是還是利用那個(gè)生成indentifier的方法乞旦,獲取identify,然后調(diào)用前面我們講過的方法獲取對應(yīng)的圖像题山。

是否將圖像緩存到內(nèi)存

- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier {
    return YES;
}

這里就是寫死的兰粉,默認(rèn)就是需要進(jìn)行緩存。

后記

本篇主要講述了關(guān)于圖像緩存方面的內(nèi)容顶瞳,包括使用標(biāo)識符或者請求進(jìn)行圖像相關(guān)的緩存操作玖姑。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市慨菱,隨后出現(xiàn)的幾起案子焰络,更是在濱河造成了極大的恐慌,老刑警劉巖符喝,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闪彼,死亡現(xiàn)場離奇詭異,居然都是意外死亡协饲,警方通過查閱死者的電腦和手機(jī)畏腕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茉稠,“玉大人描馅,你說我怎么就攤上這事《撸” “怎么了铭污?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吞获。 經(jīng)常有香客問我况凉,道長,這世上最難降的妖魔是什么各拷? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任刁绒,我火速辦了婚禮,結(jié)果婚禮上烤黍,老公的妹妹穿的比我還像新娘知市。我一直安慰自己,他們只是感情好速蕊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布嫂丙。 她就那樣靜靜地躺著,像睡著了一般规哲。 火紅的嫁衣襯著肌膚如雪跟啤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音隅肥,去河邊找鬼竿奏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛腥放,可吹牛的內(nèi)容都是我干的泛啸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼秃症,長吁一口氣:“原來是場噩夢啊……” “哼候址!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起种柑,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岗仑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后莹规,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赔蒲,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年良漱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舞虱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡母市,死狀恐怖矾兜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情患久,我是刑警寧澤椅寺,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站蒋失,受9級特大地震影響返帕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜篙挽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一荆萤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铣卡,春花似錦链韭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蝉仇,卻和暖如春旋讹,著一層夾襖步出監(jiān)牢的瞬間殖蚕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工骗村, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嫌褪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓胚股,卻偏偏與公主長得像,于是被迫代替她去往敵國和親裙秋。 傳聞我的和親對象是個(gè)殘疾皇子琅拌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

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