開源項(xiàng)目Running Life 源碼分析(二)

小小回顧

上一篇分析了項(xiàng)目的大體框架和跑步模塊一些關(guān)鍵技術(shù)的實(shí)現(xiàn)。今天這篇是Running Life源碼分析的第二篇,主要探討以下問題:
1、HealthKit框架的使用黔龟;
2、貝塞爾曲線+幀動(dòng)畫實(shí)現(xiàn)優(yōu)雅的數(shù)據(jù)展示界面;
3氏身、實(shí)現(xiàn)一個(gè)view的復(fù)用機(jī)制解決內(nèi)存暴漲的問題巍棱;

HealthKit

2014年6月2日召開的年度開發(fā)者大會上,蘋果發(fā)布了一款新的移動(dòng)應(yīng)用平臺观谦,可以收集和分析用戶的健康數(shù)據(jù),蘋果命名為“Healthkit ”桨菜。它管理著用戶得健康數(shù)據(jù)豁状,包括用戶走路的步數(shù)、消耗的卡路里倒得、體重泻红、身高等等。相信大多數(shù)微信用戶都知道微信運(yùn)動(dòng)這個(gè)功能霞掺,每天和好友PK自己的走路的步數(shù)谊路,其實(shí)在iOS端的微信不做步數(shù)統(tǒng)計(jì),它的數(shù)據(jù)源來自Healthkit菩彬。
那如何引入這個(gè)框架呢缠劝?
首先你要在你的App ID設(shè)置那里選擇支持HealthKit,然后在Xcode做相應(yīng)的設(shè)置:

title
title

這樣基本的配置工作就結(jié)束了骗灶,接下就是碼代碼了:
我將SDK和框架的相關(guān)注冊工作分離到“SDKInitProcess.h”這個(gè)文件惨恭,這樣做是為了方便對SDK注冊管理,此外還可以給AppDelegate瘦身耙旦。注冊如下:

-(void)initHealthKitSetting{
    if (![HKHealthStore isHealthDataAvailable]) {
        NSLog(@"設(shè)備不支持healthKit");
    }
    
    HKObjectType *walkingRuningDistance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    
    NSSet *healthSet = [NSSet setWithObjects:walkingRuningDistance, nil];
    
    //從健康應(yīng)用中獲取權(quán)限
    [self.healthStore requestAuthorizationToShareTypes:nil readTypes:healthSet completion:^(BOOL success, NSError * _Nullable error) {
        if (success)
        {
            NSLog(@"獲取距離權(quán)限成功");
        }
        else
        {
            NSLog(@"獲取距離權(quán)限失敗");
        }
    }];

}

-(HKHealthStore *)healthStore{
    if (!_healthStore) {
        _healthStore = [[HKHealthStore alloc]init];
    }
    return _healthStore;
}

HKObjectType是你想從HealthKit框架獲取的數(shù)據(jù)類型脱羡,針對我們的項(xiàng)目,我們需要獲取距離數(shù)據(jù)免都。
我將獲取HealthKit數(shù)據(jù)封裝在工具類的HealthKitManager中锉罐,代碼如下:

typedef void(^completeBlock)(id);

typedef void(^errorBlock)(NSError*);

/**
 *  健康數(shù)據(jù)管理對象
 */
@interface HealthKitManager : NSObject

/**
 *  全局管理類
 *
 *  @return 
 */
+ (HealthKitManager *)shareManager;

/**
 *  獲取某年某月的健康數(shù)據(jù)中路程數(shù)據(jù)(原生數(shù)據(jù))
 *
 *  @param year       年份
 *  @param month      月份
 *  @param block      成功回調(diào)
 *  @param errorBlock 失敗回調(diào)
 */
- (void)getDistancesWithYear:(NSInteger)year
                       month:(NSInteger)month
                    complete:(completeBlock) block
               failWithError:(errorBlock)errorBlock;


/**
 *  獲取某年某月的卡路里數(shù)據(jù)(計(jì)算數(shù)據(jù))
 *
 *  @param weight     體重
 *  @param year       年份
 *  @param month      月份
 *  @param block      成功回調(diào)
 *  @param errorBlock 失敗回調(diào)
 */
- (void)getKcalWithWeight:(float)weight
                     year:(NSInteger)year
                    month:(NSInteger)month
                 complete:(completeBlock) block
            failWithError:(errorBlock)errorBlock;

@end

第一個(gè)方法是從HealthKit獲取每個(gè)月份的距離數(shù)據(jù),我來帶大家看具體的實(shí)現(xiàn)代碼:

- (void)getDistancesWithYear:(NSInteger)year
                       month:(NSInteger)month
                    complete:(completeBlock) block
               failWithError:(errorBlock)errorBlock{
    
    //想獲取的數(shù)據(jù)類型绕娘,我們項(xiàng)目需要的是走路+跑步的距離數(shù)據(jù)
    HKSampleType* sampleType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    
    //按數(shù)據(jù)開始日期排序
    NSSortDescriptor* start = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO];
    
    //以下操作是為了將字符串的日期轉(zhuǎn)化為NSDate對象
    NSDateFormatter* formatter = [[NSDateFormatter alloc]init];
    [formatter setDateFormat:@"yy-MM-dd"];
    NSString* startDateStr = [NSString stringWithFormat:@"%ld-%ld-%ld",(long)year,(long)month,(long)1];
    
    //每個(gè)月第一天
    NSDate* startDate = [formatter dateFromString:startDateStr];
    
    //每個(gè)月的最后一天
    NSDate* endDate = [[NSDate alloc]initWithTimeInterval:31*24*60*60-1 sinceDate:startDate];
    
    //定義一個(gè)謂詞邏輯脓规,相當(dāng)于sql語句,我猜測healthKit底層的數(shù)據(jù)存儲應(yīng)該用的也是CoreData
    NSPredicate* predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
    
    //定義一個(gè)查詢操作
    HKSampleQuery* query = [[HKSampleQuery alloc]initWithSampleType:sampleType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:@[start] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        if (error) {
            if (errorBlock) {
                errorBlock(error);
            }
        }else{
            //一個(gè)字典险领,鍵為日期抖拦,值為距離
            NSMutableDictionary* multDict = [NSMutableDictionary dictionaryWithCapacity:30];
            
            //遍歷HKQuantitySample數(shù)組,遍歷計(jì)算每一天的距離數(shù)據(jù)舷暮,然后放進(jìn)multDict
            for (HKQuantitySample* sample in results) {
                NSString* dateStr = [formatter stringFromDate:sample.startDate] ;
                if ([[multDict allKeys]containsObject:dateStr]) {
                    int distance = (int)[[multDict valueForKey:dateStr] doubleValue];
                    distance = distance + [sample.quantity doubleValueForUnit:[HKUnit meterUnit]];
                    [multDict setObject:@(distance) forKey:dateStr];
                }else{
                    int distance = (int)[sample.quantity doubleValueForUnit:[HKUnit meterUnit]];
                    [multDict setObject: @(distance) forKey:dateStr];
                }
            }
            
            NSArray* arr = multDict.allKeys;
            
            //multDict的鍵值按日期來排序:1號~31號
            arr = [arr sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
                NSString* str1 = [NSString stringWithFormat:@"%@",obj1];
                NSString* str2 = [NSString stringWithFormat:@"%@",obj2];
                int num1 = [[str1 substringFromIndex:6] intValue];
                int num2 = [[str2 substringFromIndex:6] intValue];
                if (num1<num2) {
                    return NSOrderedAscending;
                }else{
                    return NSOrderedDescending;
                }
            }];
            
            //按排序好的鍵取得值裝進(jìn)resultArr返回給業(yè)務(wù)層
            NSMutableArray* resultArr = [NSMutableArray arrayWithCapacity:30];
            for (NSString* key in arr) {
                [resultArr addObject:multDict[key]];
            }
           
            if (block) {
                block(resultArr);
            }
           
        }
        
    }];
    
    //執(zhí)行查詢
    [self.healthStore executeQuery:query];
}

第一個(gè)方法相關(guān)講解我已經(jīng)寫在注釋里态罪;
第二個(gè)方法是根據(jù)healthKit獲取的距離數(shù)據(jù)計(jì)算出卡路里數(shù)據(jù),它是根據(jù)以下公式計(jì)算得的:
卡路里(kcal) = 公里數(shù)(km) * 體重(kg) * 1.036
那么HealthKit的相關(guān)講解就到這里下面,想了解更多內(nèi)容可以戳這里

數(shù)據(jù)展示界面

效果如下:

效果圖
效果圖

上面的日歷控件不難實(shí)現(xiàn)复颈,由NSCalendar + UICollectionView實(shí)現(xiàn),就不展開講了。這里主要分析的下面那個(gè)坐標(biāo)圖以及動(dòng)畫效果如何實(shí)現(xiàn)耗啦。
實(shí)現(xiàn)的關(guān)鍵點(diǎn):CAShapeLayer凿菩、UIBezierPath、CABasicAnimation
實(shí)現(xiàn)的代碼在"RecordShowView.m"這個(gè)類中:

坐標(biāo)系的繪畫:

- (void)drawBaseView {
    CGFloat W = self.frame.size.width;
    CGFloat H = self.frame.size.height;
    
    CGFloat smallPathAlign = (W-40)/(5*7);
    CGFloat smallPathLineH = 4;
    UIBezierPath* smallPath = [UIBezierPath bezierPath];
    for (int i = 1; i<=35; i++) {
        [smallPath moveToPoint:CGPointMake(20+smallPathAlign*i, H-20)];
        [smallPath addLineToPoint:CGPointMake(20+smallPathAlign*i, H-20-smallPathLineH)];
    }
    CAShapeLayer* smallPathLayer = [CAShapeLayer layer];
    smallPathLayer.path = smallPath.CGPath;
    smallPathLayer.strokeColor = [UIColor lightGrayColor].CGColor;
    smallPathLayer.lineWidth = 2;
    [self.layer addSublayer:smallPathLayer];
    
    
    
    UIBezierPath* frameworkPath = [UIBezierPath bezierPath];
    [frameworkPath moveToPoint:CGPointMake(20, 0)];
    [frameworkPath addLineToPoint:CGPointMake(20, H-20)];
    [frameworkPath moveToPoint:CGPointMake(20, H-20)];
    [frameworkPath addLineToPoint:CGPointMake(W-20, H-20)];

    CGFloat bigPathAlign = (W-40)/5;
    CGFloat bigPathLineH = 5;
    for (int i = 1; i<=4; i++) {
        [frameworkPath moveToPoint:CGPointMake(20+bigPathAlign*i, H-20)];
        [frameworkPath addLineToPoint:CGPointMake(20+bigPathAlign*i, H-20-bigPathLineH)];
    }
    
    [frameworkPath moveToPoint:CGPointMake(20, 20)];
    [frameworkPath addLineToPoint:CGPointMake(20+10, 20)];
    
    CAShapeLayer* frameworkLayer = [CAShapeLayer layer];
    frameworkLayer.path = frameworkPath.CGPath;
    frameworkLayer.strokeColor = [UIColor grayColor].CGColor;
    frameworkLayer.lineWidth = 2;
    [self.layer addSublayer:frameworkLayer];
    
    _textLayer = [CATextLayer layer];
    _textLayer.string = @"1200卡路里";
    _textLayer.fontSize = 12;
    _textLayer.bounds = CGRectMake(0, 0, 100, 100);
    _textLayer.foregroundColor = UIColorFromRGB(0x43B5FE).CGColor;
    _textLayer.contentsScale = [UIScreen mainScreen].scale;
    _textLayer.position = CGPointMake(20+10+55,60);
    [self.layer addSublayer:_textLayer];

}

CAShapeLayer本身沒有形狀,它的形狀來源于你給定的一個(gè)路徑帜讲,我們可以通過UIBezierPath指定路徑繪畫出各種各樣的形狀衅谷。我們實(shí)現(xiàn)的效果只需要通過畫線就可以完成,moveToPoint方法指定線的起點(diǎn)似将,addLineToPoint指定線的終點(diǎn)获黔,這樣就可以確定一條線。最后將CAShapeLayer添加到父view的圖層就可以顯示出來了在验。

柱狀圖的繪畫

實(shí)現(xiàn)代碼如下:

/**
 *  繪畫柱狀圖
 *
 *  @param values    數(shù)值數(shù)組
 *  @param lineColor 柱狀圖顏色
 *
 *  @return 柱狀圖layer
 */
-(CAShapeLayer *)drawRecordValue:(NSArray *)values lineColor:(UIColor *)lineColor{
    CGFloat W = self.frame.size.width;
    CGFloat H = self.frame.size.height;
    
    CGFloat lineHight = H- 20 * 2;
    CGFloat lineWidth = W- 40;
    CGFloat aliginW = lineWidth/(5*7);
    UIBezierPath* recordPath = [UIBezierPath bezierPath];
    CAShapeLayer *layer = [CAShapeLayer layer];
    for (int i = 1; i<values.count; i++) {
        CGFloat recordH = [values[i] intValue]*lineHight/1200 > self.frame.size.height -20? self.frame.size.height - 20:[values[i] intValue]*lineHight/1200;
        
        [recordPath moveToPoint:CGPointMake(20+aliginW*i, H-20)];
        [recordPath addLineToPoint:CGPointMake(20+aliginW*i, H-20-recordH)];
    }
    layer.path = recordPath.CGPath;
    layer.strokeColor =  lineColor.CGColor;
    layer.lineWidth = 4;
    layer.lineCap = kCALineCapRound;
    
    //設(shè)置幀動(dòng)畫
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.fromValue = @(0.0);
    animation.toValue = @(1.0);
    animation.autoreverses = NO;
    animation.duration = 0.8;
    
    [layer addAnimation:animation forKey:nil];
    
    return layer;
}

遍歷數(shù)組計(jì)算出每個(gè)柱狀圖的高度玷氏,根據(jù)高度設(shè)置繪畫的路徑,路徑確定后腋舌,給layer添加一個(gè)動(dòng)畫效果盏触,這個(gè)動(dòng)畫其實(shí)就是柱狀圖的繪畫過程,注意這里動(dòng)畫keyPath是strokeEnd块饺。
這個(gè)方法外部不能直接調(diào)用赞辩,而是通過設(shè)置柱狀圖的數(shù)值數(shù)組來間接調(diào)用。大家可以看下數(shù)值數(shù)組的setter方法授艰,這里又有一個(gè)要注意的點(diǎn)诗宣,就是設(shè)置新的柱狀圖的時(shí)候,要移除舊的柱狀圖:

/**
 *  走路+跑步卡路里數(shù)據(jù)
 *
 *  @param normalRecords
 */
- (void)setNormalRecords:(NSArray *)normalRecords {
    if (_normalLayer) {
        [_normalLayer removeFromSuperlayer];
    }
    _normalRecords = [normalRecords copy];
    _normalLayer = [self drawRecordValue:normalRecords lineColor:UIColorFromRGB(0x43B5FE)];
    [self.layer addSublayer:_normalLayer];
}

/**
 *  跑步卡路里數(shù)據(jù)
 *
 *  @param specialRecords
 */
- (void)setSpecialRecords:(NSArray *)specialRecords {
    if (_specialLayer) {
        [_specialLayer removeFromSuperlayer];
    }
    _specialRecords = [specialRecords copy];
    _specialLayer = [self drawRecordValue:specialRecords lineColor:UIColorFromRGB(0X2E38AD)];
    [self.layer addSublayer:_specialLayer];
}

設(shè)計(jì)View復(fù)用機(jī)制

應(yīng)用有這樣一個(gè)使用場景想诅,用戶可以點(diǎn)擊日歷的某一天查看那一天的跑步記錄召庞,每次記錄都會生成一張小卡片,左右滑動(dòng)可以查看每一次跑步記錄:

title
title

如果卡片視圖是直接根據(jù)記錄new出來来破,當(dāng)記錄一多就會造成內(nèi)存暴漲篮灼,嚴(yán)重時(shí)會crash。所以我設(shè)計(jì)了一個(gè)View的復(fù)用機(jī)制徘禁,解決這種多page視圖復(fù)用的問題诅诱。
源碼在"XDPageView.m"文件中,大家可以看下頭文件提供方法送朱,已做注釋:

@interface XDPageView : UIView

/**
 *  當(dāng)前頁下標(biāo)
 */
@property (nonatomic, assign, readwrite) NSInteger currentPageIndex;

/**
 *  自定義page視圖娘荡,使用的時(shí)候判斷是否有dequeueView,如果有就直接dequeueView驶沼,沒有再實(shí)例化一個(gè)新視圖炮沐,可以參考tableView cell 復(fù)用機(jī)制的使用
 */
@property (nonatomic, copy, readwrite) UIView *(^loadViewAtIndexBlock)(NSInteger pageIndex,UIView *dequeueView);
@property (nonatomic, copy, readwrite) UIView *(^loadViewAtIndexBlock)(NSInteger pageIndex,UIView *dequeueView);

/**
 *  page的數(shù)量
 */
@property (nonatomic, copy, readwrite) NSInteger(^pagesCount)();


@end

以下設(shè)計(jì)思路:
1、創(chuàng)建兩個(gè)容器回怜,一個(gè)用于裝可見視圖大年,最大容量為2,我們假設(shè)當(dāng)前頁面和下一頁面屬于可見;一個(gè)用于裝復(fù)用視圖翔试,最大容量為1轻要。為了記錄可見視圖的下標(biāo)(方便判斷頁面狀態(tài),頁面是屬于當(dāng)前頁垦缅、上一頁還是下一頁)冲泥,裝可視圖的容器,我使用字典來設(shè)計(jì)壁涎;對于復(fù)用池里的視圖無需考慮頁面的狀態(tài)和順序凡恍,所以我使用集合來設(shè)計(jì):

/**
 *  可見視圖以及下標(biāo),可見視圖最大數(shù)量為2
 */
@property (nonatomic, strong, readwrite) NSMutableDictionary *visibleViewsItemMap;

/**
 *  容量最大為1的復(fù)用池
 */
@property (nonatomic, strong, readwrite) NSMutableSet *dequeueViewPool;

2粹庞、每當(dāng)滑進(jìn)一個(gè)頁面咳焚,滑出的頁面裝入復(fù)用容器洽损,當(dāng)前頁面和下一頁面裝入可見容器(下一頁屬于即將可見庞溜,它復(fù)用“復(fù)用容器”里的視圖,復(fù)用視圖一旦被使用就移出“復(fù)用容器”):

- (void)loadViewsForNeed {
    CGFloat itemW = _pageSize.width;
    if (itemW) {
        CGFloat W = self.bounds.size.width;
        //當(dāng)前頁的下標(biāo)
        NSInteger startIndex = floorf((float)_scrollView.contentOffset.x / _pageSize.width);
 
        //如果page數(shù)大于1則設(shè)置可見item數(shù)為2碑定,如果只有一頁流码,那么可見就只有1個(gè)
        NSInteger numberOfVisibleItems = (_scrollView.contentOffset.x/W) == 0.0 ? 1 : 2;
        numberOfVisibleItems = MIN(numberOfVisibleItems, _pageCount);
        
        //當(dāng)前頁和它的下一頁設(shè)置為可見的
        NSMutableSet *visibleIndexs = [NSMutableSet set];
        for (int i = 0; i < numberOfVisibleItems; i++) {
            NSInteger index = startIndex + i;
            [visibleIndexs addObject:@(index)];
        }
        
        for (NSNumber *num in [_visibleViewsItemMap allKeys]) {
            //對于已不可見的視圖,移出可見視圖加入復(fù)用池
            if (![visibleIndexs containsObject:num]) {
                UIView *view = _visibleViewsItemMap[num];
                [self queueInPoolWithView:view];
                [view removeFromSuperview];
                [_visibleViewsItemMap removeObjectForKey:num];
            }
        }
        
        for (NSNumber *num in visibleIndexs) {
            UIView *view = _visibleViewsItemMap[num];
            //加載新的可見視圖延刘,加載完成后加入可視圖容器中
            if (view == nil) {
                view = [self loadItemViewAtIndex:[num integerValue]];
                
                _visibleViewsItemMap[num] = view;
                
                [_scrollView addSubview:view];
            }
        }
    }
}

小結(jié)

項(xiàng)目的主要細(xì)節(jié)已經(jīng)分析完漫试,大家有什么的地方不懂或者有疑問的,可以在github issue 我或者在評論區(qū)提出碘赖。
項(xiàng)目地址:github.com/caixindong/Running-Life---iOS驾荣。
下一篇博文預(yù)告:XDNetworking網(wǎng)絡(luò)框架的設(shè)計(jì)及源碼分析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末普泡,一起剝皮案震驚了整個(gè)濱河市播掷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撼班,老刑警劉巖歧匈,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砰嘁,居然都是意外死亡件炉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門矮湘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斟冕,“玉大人,你說我怎么就攤上這事缅阳」玻” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孤里。 經(jīng)常有香客問我伏伯,道長,這世上最難降的妖魔是什么捌袜? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任说搅,我火速辦了婚禮,結(jié)果婚禮上虏等,老公的妹妹穿的比我還像新娘弄唧。我一直安慰自己,他們只是感情好霍衫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布候引。 她就那樣靜靜地躺著,像睡著了一般敦跌。 火紅的嫁衣襯著肌膚如雪澄干。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天柠傍,我揣著相機(jī)與錄音麸俘,去河邊找鬼。 笑死惧笛,一個(gè)胖子當(dāng)著我的面吹牛从媚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播患整,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拜效,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了各谚?” 一聲冷哼從身側(cè)響起紧憾,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘲碧,沒想到半個(gè)月后稻励,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愈涩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年望抽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片履婉。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡煤篙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毁腿,到底是詐尸還是另有隱情辑奈,我是刑警寧澤苛茂,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鸠窗,受9級特大地震影響妓羊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜稍计,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一躁绸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臣嚣,春花似錦净刮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怎虫,卻和暖如春暑认,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揪垄。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工穷吮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逻翁,地道東北人饥努。 一個(gè)月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像八回,于是被迫代替她去往敵國和親酷愧。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

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