iOS7、8、9相冊適配

相冊適配


前言

由于在iOS8及以后蘋果將原有的操作相冊的ALAssetsLibrary framework替換為Photos framework,所以,如果在應用中使用到的相冊需要支持iOS8以下的系統(tǒng)版本的話,就需要了解Photos framework以做不同的版本適配。

一、iOS8以下

1. 幾個重要的實體概念

  • ALAsset(iOS8及以后使用PHAsset)
    一個ALAsset實例對象代表一個資源實體,比如一張圖片、一個視頻。共有三種類型:

    ALAssetTypePhoto // 圖片
    ALAssetTypeVideo // 視頻
    ALAssetTypeUnknown // 未知
    

通過這個實例,你可以獲取到這個資源的創(chuàng)建時間、資源類型、縮略圖、二進制數(shù)據(jù)等信息。

  • ALAssetsGroup(iOS8及以后使用PHAssetCollection)
    一個ALAssetsGroup實例對象代表一組資源的集合,也就是一個相冊,可以是系統(tǒng)默認存在的相冊(相機膠卷),也可以是開發(fā)者給用戶創(chuàng)建的自定義相冊(QQ)。
    通過它,你可以獲取到這個相冊的名稱、封面縮略圖等。

  • ALAssetsLibrary(iOS8及以后使用PHPhotoLibrary)
    一個ALAssetsLibrary實例對象對所有的相冊資源進行索引。
    使用它,你可以獲取指定類型的相冊、單張圖片等對象,也可以添加新的自定義相冊或者圖片到相薄。如果你想要知道有沒有獲取到系統(tǒng)相薄的訪問權(quán)限,同樣需要用到它。

2. 實體相關(guān)API

ALAssetsLibrary

在iOS7及以下系統(tǒng)中,如果你想要獲取相冊中的資源,或者對相冊進行操作,那么你先要創(chuàng)建一個ALAssetsLibrary實例對象。

  • 獲取指定類型的相冊

     - (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
    

注意
由于這里的遍歷都是異步的操作,所以ALAssetsLibrary的實例對象需要被一個靜態(tài)變量或者成員變量引用來保證不被銷毀,回調(diào)的Block才能保證被成功調(diào)用。下面同此處。

  • 根據(jù)一個相冊URL獲取這個相冊

     - (void)groupForURL:(NSURL *)groupURL resultBlock:(ALAssetsLibraryGroupResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
    
  • 創(chuàng)建一個相冊

     - (void)addAssetsGroupAlbumWithName:(NSString *)name resultBlock:(ALAssetsLibraryGroupResultBlock)resultBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock
    
  • 相冊授權(quán)狀態(tài)

     + (ALAuthorizationStatus)authorizationStatus
    

ALAssetsGroup

iOS7及以下系統(tǒng)的中每個相冊都是一個ALAssetsGroup實例,你可以使用這個實例獲取這個相冊的相關(guān)信息。

  • 獲取相冊信息

     - (id)valueForProperty:(NSString *)property  
    

參數(shù)property包含以下類型:
ALAssetsGroupPropertyName
ALAssetsGroupPropertyType
ALAssetsGroupPropertyPersistentID
ALAssetsGroupPropertyURL

  • 封面圖

     - (CGImageRef)posterImage
    
  • 相冊包含實體(照片、視頻)的數(shù)量

     - (NSInteger)numberOfAssets
    
  • 過濾規(guī)則

     - (void)setAssetsFilter:(ALAssetsFilter *)filter
    

注意
參數(shù)中的filter是一個ALAssetsFilter實例,這個實例只有三種類型:

    + (ALAssetsFilter *)allPhotos; // 所有圖片

    + (ALAssetsFilter *)allVideos; // 所有視頻

    + (ALAssetsFilter *)allAssets; // 所有視頻及圖片

在使用- (NSInteger)numberOfAssets獲取相冊實體數(shù)量時,會依賴該過濾規(guī)則。比如一個相薄中存在5個視頻和5張圖片,如果指定allPhotos,則numberOfAssets返回值為5。同樣使用- (void)enumerateAssetsUsingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock獲取相冊中的所有資源時,也只能獲取到指定過濾規(guī)則下的資源。

  • 使用相應遍歷規(guī)則獲取相冊中的所有ALAsset資源

     - (void)enumerateAssetsWithOptions:(NSEnumerationOptions)options usingBlock:(ALAssetsGroupEnumerationResultsBlock)enumerationBlock
    

3. 使用示例

  • 獲取所有相冊,并過濾相冊中的視頻

    + (void)getAssetsGroupsForIos8BelowSuccess:(void (^)(NSMutableArray *))success failure:(void (^)(NSError *error))failure {
    NSMutableArray *assetsGroups = [NSMutableArray array];
    [[self library] enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
        if (group != nil) {
            [group setAssetsFilter:[ALAssetsFilter allPhotos]];
            if (group.numberOfAssets > 0) {
                [assetsGroups addObject:group];
            }
        } else {
            if (success) {
                success(assetsGroups);
            }
        }
    } failureBlock:^(NSError *error) {
        if (failure) {
            failure(error);
        }
    }];
    

}

  • (ALAssetsLibrary *)library {
    static ALAssetsLibrary *library;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    library = [[ALAssetsLibrary alloc] init];
    });
    return library;
    }
  • 獲取一個相冊中的所有資源

    + (void)getTimeLineSectionModelsForIos8BelowWithGroup:(MRAlbumGroupModel *)group success:(void (^)(NSMutableArray *))success failure:(void (^)(NSError *))failure {
    NSMutableArray *sectionModels = [NSMutableArray array];
    [group.assetGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
        if(result) {
            [sectionModels addObject:result];
        }
    }];
    if (success != nil && sectionModels.count > 0) {
        success(sectionModels);
    }
    if (failure != nil && sectionModels.count == 0) {
        failure(nil);
    }
    

}
```

二、iOS8及以上

1. 幾個重要的實體概念

與ALAssetsLibrary framework對應的幾個實體

  • PHAsset
    一個PHAsset實例對象與ALAsset類似,代表一個資源實體,比如一張圖片、一個視頻。與ALAsset不同之處在于,多了一種實體類型,共四種類型:

    PHAssetMediaTypeUnknown = 0,
    PHAssetMediaTypeImage   = 1,
    PHAssetMediaTypeVideo   = 2,
    PHAssetMediaTypeAudio   = 3,
    

同時,還多了更具體的子類型PHAssetMediaSubtype:

```
PHAssetMediaSubtypeNone               = 0,

// Photo subtypes
PHAssetMediaSubtypePhotoPanorama      = (1UL << 0),
PHAssetMediaSubtypePhotoHDR           = (1UL << 1),
PHAssetMediaSubtypePhotoScreenshot PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = (1UL << 2),
PHAssetMediaSubtypePhotoLive PHOTOS_AVAILABLE_IOS_TVOS(9_1, 10_0) = (1UL << 3),

// Video subtypes
PHAssetMediaSubtypeVideoStreamed      = (1UL << 16),
PHAssetMediaSubtypeVideoHighFrameRate = (1UL << 17),
PHAssetMediaSubtypeVideoTimelapse     = (1UL << 18),
```

通過這個實例,除了可以獲取到這個資源的創(chuàng)建時間、資源類型、縮略圖、二進制數(shù)據(jù)等信息,還可以獲取到location等位置信息。

  • PHCollection
    PHCollection是個基類,它有兩個子類。分別是PHAssetCollectionPHCollectionList,PHAssetCollection代表 Photos 中的相冊,PHCollectionList代表 Photos 中的文件夾。PHCollectionList里可嵌套PHAssetCollection,也可以嵌套自身類型,同時支持多重嵌套。
    一個PHAssetCollection實例對象與ALAssetsGroup類似,代表一組資源的集合,也就是一個相冊。
    通過它,你可以獲取到這個相冊的名稱、封面縮略圖。
    以及相冊類型PHAssetCollectionType

    PHAssetCollectionTypeAlbum      = 1, // 自定義相冊,如QQ
    PHAssetCollectionTypeSmartAlbum = 2, // 相機膠卷、我的照片流、屏幕截圖、全景照片等
    PHAssetCollectionTypeMoment     = 3, // 時刻
    

    相冊子類型PHAssetCollectionSubtype

    // PHAssetCollectionTypeAlbum regular subtypes
    PHAssetCollectionSubtypeAlbumRegular         = 2,
    PHAssetCollectionSubtypeAlbumSyncedEvent     = 3,
    PHAssetCollectionSubtypeAlbumSyncedFaces     = 4,
    PHAssetCollectionSubtypeAlbumSyncedAlbum     = 5,
    PHAssetCollectionSubtypeAlbumImported        = 6,
        
    // PHAssetCollectionTypeAlbum shared subtypes
    PHAssetCollectionSubtypeAlbumMyPhotoStream   = 100,
    PHAssetCollectionSubtypeAlbumCloudShared     = 101,
        
    // PHAssetCollectionTypeSmartAlbum subtypes
    PHAssetCollectionSubtypeSmartAlbumGeneric    = 200,
    PHAssetCollectionSubtypeSmartAlbumPanoramas  = 201,
    PHAssetCollectionSubtypeSmartAlbumVideos     = 202,
    PHAssetCollectionSubtypeSmartAlbumFavorites  = 203,
    PHAssetCollectionSubtypeSmartAlbumTimelapses = 204,
    PHAssetCollectionSubtypeSmartAlbumAllHidden  = 205,
    PHAssetCollectionSubtypeSmartAlbumRecentlyAdded = 206,
    PHAssetCollectionSubtypeSmartAlbumBursts     = 207,
    PHAssetCollectionSubtypeSmartAlbumSlomoVideos = 208,
    PHAssetCollectionSubtypeSmartAlbumUserLibrary = 209,
    PHAssetCollectionSubtypeSmartAlbumSelfPortraits PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 210,
    PHAssetCollectionSubtypeSmartAlbumScreenshots PHOTOS_AVAILABLE_IOS_TVOS(9_0, 10_0) = 211,
        
    // Used for fetching, if you don't care about the exact subtype
    PHAssetCollectionSubtypeAny = NSIntegerMax
    
  • PHPhotoLibrary
    PHPhotoLibrary是個單例對象,與ALAssetsLibrary相比發(fā)生了較大變化,只能申請獲取PHOtos權(quán)限以及授權(quán)狀態(tài)獲取等。
    使用這個單例你也可以注冊相冊改動的監(jiān)聽者,在相冊發(fā)生變化(比如添加或?qū)肓诵聢D片)時,做一些刷新或其他處理。

新的實體

在iOS8及以上的相冊資源獲取中,都是使用fetch相關(guān)API的形式,過程類似Core Data。匹配資源的過程自然需要匹配規(guī)則,最終匹配結(jié)果也需要一個集合來記錄。

  • PHFetchOptions
    PHFetchOptions的實例對象代表獲取資源時的匹配規(guī)則。
    可以指定資源排序規(guī)則(NSArray<NSSortDescriptor *> *sortDescriptors;)、資源類型規(guī)則(NSPredicate *predicate)、最大數(shù)量(NSUInteger fetchLimit)等。

  • PHFetchResult
    PHFetchResult的實例對象代表相冊資源的匹配結(jié)果集合。它包含零個或多個符合匹配規(guī)則的資源,這些資源可以是PHAssetCollection對象,也可以是PHAsset對象。

  • PHImageManager
    PHImageManager是一個單例對象,不需要你手動創(chuàng)建,這個單例對象可以讓你獲取到一個PHAsset資源的實際二進制數(shù)據(jù)——如一張圖片數(shù)據(jù)。

2. 實體相關(guān)API

PHAssetCollection

在iOS8及以上系統(tǒng)中,獲取相冊不需要創(chuàng)建實例,直接使用PHAssetCollection的類方法進行操作即可。

  • 獲取指定類型的相冊

     // Fetch asset collections of a single type and subtype provided (use PHAssetCollectionSubtypeAny to match all subtypes)
     + (PHFetchResult<PHAssetCollection *> *)fetchAssetCollectionsWithType:(PHAssetCollectionType)type subtype:(PHAssetCollectionSubtype)subtype options:(nullable PHFetchOptions *)options;
    
  • 基本屬性

    @property (nonatomic, strong, readonly, nullable) NSString *localizedTitle; // 相冊標題
    @property (nonatomic, assign, readonly) PHAssetCollectionType assetCollectionType; // 相冊類型
    @property (nonatomic, assign, readonly) PHAssetCollectionSubtype assetCollectionSubtype; // 子類型
    @property (nonatomic, assign, readonly) NSUInteger estimatedAssetCount; // 預估資源數(shù)量
    @property (nonatomic, strong, readonly, nullable) NSDate *startDate; // 開始日期
    @property (nonatomic, strong, readonly, nullable) NSDate *endDate; // 結(jié)束日期
    @property (nonatomic, strong, readonly, nullable) CLLocation *approximateLocation; // 位置信息
    @property (nonatomic, strong, readonly) NSArray<NSString *> *localizedLocationNames; // 位置名稱
    

注意
estimatedAssetCount并不是一個準確的值,當PHAssetCollection對象不能馬上計算出當前相冊中的資源數(shù)量時,會返回NSNotFound,如果想要獲取資源的具體數(shù)量,需要使用PHAsset來fetch所有資源,計算資源數(shù)量。

PHAsset

  • 獲取某相冊中的PHAsset資源

     + (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
    
  • 獲取某相冊的封面資源

     + (nullable PHFetchResult<PHAsset *> *)fetchKeyAssetsInAssetCollection:(PHAssetCollection *)assetCollection options:(nullable PHFetchOptions *)options;
    

注意
這個API可以獲取到系統(tǒng)默認的一些封面圖資源,這個結(jié)果由零個或多個PHAsset組成,在相冊是smartAlbum類型的情況下,可能會有零個結(jié)果的情況。

  • 獲取中Photos中的所有PHAsset資源

     + (PHFetchResult<PHAsset *> *)fetchAssetsWithOptions:(nullable PHFetchOptions *)options;
    

注意
這里并不是獲取某個相冊中的PHAsset資源,而是手機中所有的PHAsset資源。
比如手機中有10個相冊,每個相冊中10個PHAsset資源,如果不指定PHFetchOptions,使用該方法會獲取到所有的100個PHAsset資源。

  • 獲取Photos中指定資源類型的所有PHAsset資源

     + (PHFetchResult<PHAsset *> *)fetchAssetsWithMediaType:(PHAssetMediaType)mediaType options:(nullable PHFetchOptions *)options;
    

參數(shù)中的mediaType可選:

```
PHAssetMediaTypeUnknown = 0,
PHAssetMediaTypeImage   = 1,
PHAssetMediaTypeVideo   = 2,
PHAssetMediaTypeAudio   = 3,
```

PHImageManager

  • 獲取PHAsset圖片資源的圖片數(shù)據(jù)

     - (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
    

注意
參數(shù)中的PHImageRequestOptions對象可以設(shè)置目標圖片的一些屬性,其中synchronous表示是否同步獲取,默認是NO,也就是異步獲取。

3. 使用示例

  • 獲取指定類型的相冊

    + (NSMutableArray *)getCollecionsWithSmartAlbumSubtype:(PHAssetCollectionSubtype)subtype {
    PHFetchOptions *userAlbumsOptions = [PHFetchOptions new];
    PHFetchResult *userAlbumsResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                                               subtype:PHAssetCollectionSubtypeAny
                                                                               options:userAlbumsOptions];
    PHFetchResult *userSmartAlbumsResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
                                                                                    subtype:subtype
                                                                                    options:userAlbumsOptions];
    NSMutableArray *collections = [NSMutableArray array];
    void (^AlbumEnumerateObjectsUsingBlock)(PHAssetCollection *, NSUInteger idx, BOOL *) = ^(PHAssetCollection * _Nonnull collection, NSUInteger idx, BOOL * _Nonnull stop) {
        if (collection.estimatedAssetCount == 0) {
            return ;
        }
        NSUInteger numberOfAssets = 0;
        PHFetchResult *assetsResult = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
        numberOfAssets = [assetsResult countOfAssetsWithMediaType:PHAssetMediaTypeImage];
        if (numberOfAssets == 0) {
            return;
        }
        [collections addObject:collection];
    };
    [userSmartAlbumsResult enumerateObjectsUsingBlock:AlbumEnumerateObjectsUsingBlock];
    [userAlbumsResult enumerateObjectsUsingBlock:AlbumEnumerateObjectsUsingBlock];
    return collections;
    

}
```

  • 獲取一個相冊中的所有圖片資源,按創(chuàng)建時間降序排序

    + (void)getTimeLineSectionModelsForIos8AboveWithGroup:(MRAlbumGroupModel *)group success:(void (^)(NSMutableArray *))success failure:(void (^)(NSError *))failure {
    PHFetchResult *assetsResult = [PHAsset fetchAssetsInAssetCollection:group.collection options:[self fetchOptions]];
    NSMutableArray *sectionModels = [NSMutableArray array];
    [assetsResult enumerateObjectsUsingBlock:^(PHAsset * _Nonnull asset, NSUInteger idx, BOOL * _Nonnull stop) {
        [sectionModels addObject:asset];
    }];
    if (success != nil && sectionModels.count > 0) {
        success(sectionModels);
    }
    if (failure != nil && sectionModels.count == 0) {
        failure(nil);
    }
    

}

  • (PHFetchOptions *)fetchOptions {
    PHFetchOptions *fetchOptions = [PHFetchOptions new];
    fetchOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType = %@", @(PHAssetMediaTypeImage)];
    fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
    return fetchOptions;
    }
    
    

三、適配參考

我在不同系統(tǒng)的相冊適配中采用適配器的方式進行的適配,僅供參考。

1. 適配器

相冊適配主要是為了解決在iOS8以上的系統(tǒng)中,使用ALLibrary相關(guān)API可能存在一些不兼容的問題,導致資源獲取不一致情況的出現(xiàn)。

在業(yè)務展現(xiàn)上并不期望因系統(tǒng)不同而給用戶差別較大的體驗,所以可以只針對相冊資源數(shù)據(jù)獲取的數(shù)據(jù)測適配即可,而無需改動UI。

這種場景可以在數(shù)據(jù)層對ALAssetsGroupPHAssetCollection以及ALAssetPHAsset做抽象,抽取適配器即可。

2. 簡單示例

  • AssetGroupModel

    @interface AlbumGroupModel : NSObject
    
    @property (nonatomic, strong) UIImage *posterImage;
    @property (nonatomic, assign) NSUInteger numberOfAssets;
    @property (nonatomic, copy) NSString *assetsGroupPropertyName;
    
    @property (nonatomic, strong) PHAssetCollection *collection;
    @property (nonatomic, strong) ALAssetsGroup *assetGroup;
    
    @end
    @implementation AlbumGroupModel
    
  • (UIImage *)posterImage {
    if (_posterImage == nil) {
    if ([XSLAppInfoTool systemVersion] < 8.0) {
    _posterImage = [UIImage imageWithCGImage:self.assetGroup.posterImage];
    } else {
    PHFetchResult *groupResult = [PHAsset fetchAssetsInAssetCollection:self.collection options:self.class.fetchOptions];
    PHAsset *asset = groupResult.firstObject;
    PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init];
    requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact;

          CGFloat scale = [UIScreen mainScreen].scale;
          CGFloat dimension = 80.0f;
          CGSize size = CGSizeMake(dimension * scale, dimension * scale);
          __block UIImage *resultImage = nil;
          [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:requestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
              resultImage = result;
          }];
          _posterImage = resultImage;
      }
    

    }
    return _posterImage;
    }
    @end

    
    
  • AssetModel

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

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