iOS定時器

1.NSTimer

iOS中最基本的定時器布隔。其通過RunLoop來實現(xiàn)离陶,一般情況下較為準確,但當當前循環(huán)耗時操作較多時衅檀,會出現(xiàn)延遲問題招刨。同時,也受所加入的RunLoop的RunLoopMode影響哀军。

NSTimer的類方法

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
//iOS10.0之后可以用的方法
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

NSTimer的對象方法
這兩個方法多了一個參數(shù)date沉眶,這個參數(shù)可以指定定時器什么時候開啟,創(chuàng)建完之后需要手動加入Runloop

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
- (void)fire;
//iOS10.0之后可以使用
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

可以看到定時器創(chuàng)建的類方法都分為invocation和selector兩種方式杉适。

1.1Timer定時器的創(chuàng)建

1.1.1傳NSInvocation方法創(chuàng)建定時器

NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:@selector(timered)];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = @selector(timered);
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 invocation:invocation repeats:YES];

- (void)timered{
    NSLog(@"定時器被調(diào)用");
}

1.1.2傳SEL方式創(chuàng)建定時器

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timered) userInfo:nil repeats:YES];

1.1.3block方式創(chuàng)建定時器

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"定時器被調(diào)用");
    }];

1.1.4NSTimer的fire方法

調(diào)用了fire方法之后會立即執(zhí)行定時器的方法谎倔,fire方法不會改變預(yù)定周期性調(diào)度。即調(diào)用完fire方法之后不會從當前時間重新開始計算時間間隔猿推,還是會從上一次計算時間間隔片习。
定時器如果不循環(huán)調(diào)用,提前調(diào)用了fire方法,不會在時間到了之后在調(diào)用一次藕咏,因為執(zhí)行一次之后任務(wù)就結(jié)束了状知。

NSLog(@"當前時間");
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(timered) userInfo:nil repeats:YES];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [timer fire];
    });

運行結(jié)果:

2020-03-02 17:54:02.436750+0800 Test[46183:3046157] 當前時間
2020-03-02 17:54:07.438237+0800 Test[46183:3046157] 定時器被調(diào)用
2020-03-02 17:54:12.439445+0800 Test[46183:3046157] 定時器被調(diào)用

定時器時間間隔設(shè)置了10秒,第五秒的時候調(diào)用了一次fire方法侈离,定時器第二次調(diào)用是在第10秒的時候试幽,而不是15秒的時候。

定時器如果不循環(huán)調(diào)用卦碾,提前調(diào)用了fire方法铺坞,不會在時間到了之后在調(diào)用一次,因為執(zhí)行一次之后任務(wù)就結(jié)束了洲胖。

NSLog(@"當前時間");
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(timered) userInfo:nil repeats:NO];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [timer fire];
    });

運行結(jié)果:

2020-03-02 17:56:39.859278+0800 Test[46250:3050494] 當前時間
2020-03-02 17:56:44.860940+0800 Test[46250:3050494] 定時器被調(diào)用

定時器在5秒之后調(diào)用一次就不再調(diào)用济榨。
1.1.5timerWithTimeInterval和scheduledTimerWithTimeInterval的區(qū)別
scheduledTimerWithTimeInterval創(chuàng)建的時候就已經(jīng)添加到runloop,
通過timerWithTimeInterval創(chuàng)建定時器之后需要手動添加到runloop才能開始運行,因為定時器的運行是依賴runloop的绿映,xcode中對方法的解釋
scheduledTimerWithTimeInterval

Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the current run loop in the default mode.

timerWithTimeInterval

Creates and returns a new NSTimer object initialized with the specified block object. This timer needs to be scheduled on a run loop (via -[NSRunLoop addTimer:]) before it will fire.

1.2定時器循環(huán)引用出現(xiàn)的原因

把定時器在一個控制器中創(chuàng)建擒滑,在控制器的dealloc方法中銷毀定時器。
通過NSInvocation叉弦、selector和block三種方式創(chuàng)建定時器丐一,分別在控制器的dealloc中銷毀定時器

- (void)dealloc{
    NSLog(@"控制器被銷毀");
    [self.timer invalidate];
    self.timer = nil;
}

運行發(fā)現(xiàn),當控制器被pop時淹冰,只有通過block方式創(chuàng)建的定時器會調(diào)用“控制器被銷毀”库车。說明其他兩種方式都會造成控制器無法釋放,造成內(nèi)存泄漏樱拴。
如果把是否循環(huán)的參數(shù)改成NO柠衍,表示定時器只執(zhí)行一次,則控制器也能被銷毀晶乔。

1.2.1定時器造成循環(huán)引用的原因

因為定時器要被加到runloop中才能運行珍坊,所以定時器被runloop強引用,因為定時器在運行時需要調(diào)用傳入的target的方法正罢,target一般都是控制器阵漏,所以定時器強引用了控制器,定時器的銷毀又放在控制器的dealloc方法中翻具,所以一直無法釋放袱饭。

1.2.2 不會造成循環(huán)引用的情況

  • 1.非重復(fù)計時器,即repeat參數(shù)傳NO的呛占,因為執(zhí)行完一次之后會直接失效虑乖。相當于調(diào)用了invalidate方法,runloop會把定時器移除晾虑。所以控制器就可以被銷毀了疹味。蘋果文檔描述如下
//非重復(fù)計時器在觸發(fā)后立即使自身失效仅叫。
 A nonrepeating timer invalidates itself immediately after it fires. 
  • 2.通過iOS10.0之后的新方法,定時器調(diào)用block糙捺,方法的介紹中描述如下
//阻塞定時器執(zhí)行體;在執(zhí)行時诫咱,計時器本身作為參數(shù)傳遞給這個塊,以幫助避免循環(huán)引用
- parameter:  block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references

1.3循環(huán)引用的解決

由于造成循環(huán)引用的原因是runloop強引用NSTimer,NSTimer強引用控制器洪灯,所以我們可以讓NSTimer不再強引用控制器坎缭,即在創(chuàng)建NSTimer的時候傳入的target為另一個對象,用來相應(yīng)定時器签钩。
具體步驟:
1.創(chuàng)建類YYTimerResponse類掏呼,在類中時間NSTimer的調(diào)用方法"- (void)timered"

#import "YYTimerResponse.h"

@implementation YYTimerResponse
- (void)timered{
    NSLog(@"在YYTimerResponse中定時器被調(diào)用");
}
- (void)dealloc{
    NSLog(@"YYTimerResponse被銷毀");
}
@end

2.在控制器中添加定時器,并且在dealloc中銷毀定時器

- (void)viewDidLoad {
    [super viewDidLoad];

    YYTimerResponse *timeResponse = [[YYTimerResponse alloc] init];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:timeResponse selector:@selector(timered) userInfo:nil repeats:YES];
}
- (void)dealloc{
    NSLog(@"控制器被銷毀");
    [self.timer invalidate];
    self.timer = nil;
}

運行之后定時器開始調(diào)用铅檩,控制器返回之后打印如下

2020-03-02 18:47:46.879168+0800 Test[47229:3134132] 在YYTimerResponse中定時器被調(diào)用
2020-03-02 18:47:47.879918+0800 Test[47229:3134132] 在YYTimerResponse中定時器被調(diào)用
2020-03-02 18:47:48.116563+0800 Test[47229:3134132] 控制器被銷毀
2020-03-02 18:47:48.116796+0800 Test[47229:3134132] YYTimerResponse被銷毀

因為此時不再強引用控制器憎夷,所以當控制器返回時,控制器的dealloc方法被調(diào)用昧旨,在dealloc方法中調(diào)用了[self.timer invalidate];拾给,所以NSTimer被移除runloop,控制器被銷毀所以控制器也不強引用NSTimer了,所以NSTimer也要被釋放兔沃,所以YYTimerResponse也被銷毀蒋得。

1.4在子線程啟動定時器

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"當前線程%@", [NSThread currentThread]);
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timered) userInfo:nil repeats:YES];
    });
- (void)timered{
    NSLog(@"定時器被調(diào)用,當前線程:%@", [NSThread currentThread]);
}

運行結(jié)果:

2020-03-02 19:04:50.483133+0800 Test[47650:3162147] 當前線程<NSThread: 0x6000013c1a00>{number = 3, name = (null)}

運行之后發(fā)現(xiàn)定時器沒有執(zhí)行
因為子線程的runloop默認沒有開啟
所以需要在創(chuàng)建完定時器之后調(diào)用“[[NSRunLoop currentRunLoop] run];”乒疏,開啟定時器额衙。
因為子線程也可以強引用NSTimer,所以此時控制器也不會被銷毀,所以還是需要像1.3中一樣解決循環(huán)引用的問題
所以代碼修改如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"當前線程%@", [NSThread currentThread]);
        YYTimerResponse *timeResponse = [[YYTimerResponse alloc] init];
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:timeResponse selector:@selector(timered) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] run];
    });

運行結(jié)果:發(fā)現(xiàn)控制器pop之后缰雇,定時器還是無法停止
把target設(shè)置為其他對象后,控制器的dealloc方法仍然無法調(diào)用的原因:因為在開啟異步操作的block中強引用了self,即子線程的runloop強引用了控制器追驴,所以控制器無法被銷毀械哟,把self弱引用。
所以最終代碼如下:

-(void)viewDidLoad{
[super viewDidLoad];
__weak __typeof__(self) weakSelf = self;
    self.timeResponse = [[YYTimerResponse alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        NSLog(@"當前線程%@", [NSThread currentThread]);
        weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf.timeResponse selector:@selector(timered) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] run];
        weakSelf.thread = [NSThread currentThread];
    });
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
    self.timeResponse = nil;
    NSLog(@"控制器被銷毀");
}

打印結(jié)果:

2020-03-03 16:03:48.477618+0800 Test[55881:3549309] 當前線程<NSThread: 0x600001e4c240>{number = 3, name = (null)}
2020-03-03 16:03:49.479146+0800 Test[55881:3549309] 在YYTimerResponse中定時器被調(diào)用,當前線程<NSThread: 0x600001e4c240>{number = 3, name = (null)}
2020-03-03 16:03:50.480857+0800 Test[55881:3549309] 在YYTimerResponse中定時器被調(diào)用,當前線程<NSThread: 0x600001e4c240>{number = 3, name = (null)}
2020-03-03 16:03:51.483406+0800 Test[55881:3549309] 在YYTimerResponse中定時器被調(diào)用,當前線程<NSThread: 0x600001e4c240>{number = 3, name = (null)}
2020-03-03 16:03:53.939806+0800 Test[55881:3549256] YYTimerResponse被銷毀
2020-03-03 16:03:53.939990+0800 Test[55881:3549256] 控制器被銷毀

在上面的代碼中殿雪,除了把self弱引用之外暇咆,還手動把YYTimerResponse對象設(shè)置為nil,因為YYTimerResponse對象也被強引用了丙曙,無法銷毀爸业。

1.5定時器加入Runloop的模式(有時無法響應(yīng))

在進行UI交互的時候(如tableView的滑動時),runloop所在的模式是UITrackingRunLoopMode亏镰,而在把定時器默認加入runloop的時候會加入"NSDefaultRunLoopMode"
runloop執(zhí)行任務(wù)時會在Mode間切換扯旷,所以在UI交互時無法響應(yīng)定時器。

1.5.1解決方法1: 再加入runloop時把模式設(shè)置為NSRunLoopCommonModes

把定時器添加到runloop時模式設(shè)置為"NSRunLoopCommonModes",這個模式并不是一種Mode索抓,而是一種特殊的標記钧忽,關(guān)聯(lián)的有一個set(默認包含NSDefaultRunLoopMode毯炮、NSModalPanelRunLoopModeNSEventTrackingRunLoopMode) 耸黑。
代碼:

YYTimerResponse *timeResponse = [[YYTimerResponse alloc] init];
    self.timer = [NSTimer timerWithTimeInterval:1 target:timeResponse selector:@selector(timered) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

1.5.3解決方法2:把定時器加入子線程

由于UI交互是在主線程桃煎,所以把定時器加入子線程的Runloop,就不用管加入的模式,因為是兩個runloop大刊,沒有關(guān)聯(lián)为迈。

2.GCD中的定時器

GCD中的Dispatch Source其中的一種類型是DISPATCH_SOURCE_TYPE_TIMER,可以實現(xiàn)定時器的功能缺菌。
dispatch源監(jiān)聽系統(tǒng)內(nèi)核對象并處理葫辐,其可以實現(xiàn)更加精準的定時效果。
GCD的定時器不是通過runloop實現(xiàn)的男翰,所以不會被runloop強引用另患,需要當前對象強引用,否則會直接被釋放蛾绎。因此GCD的定時器也沒有循環(huán)引用的問題昆箕。
使用步驟:

NSLog(@"當前時間");
    //設(shè)置定時器回調(diào)執(zhí)行所在的隊列
    dispatch_queue_t queue = dispatch_get_main_queue();
    //創(chuàng)建dispatch_source_t類型的對象gcdTimer
    self.gcdTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //設(shè)置定時器開始時間,2秒后
    dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC));
    //時間間隔
    uint64_t intervalTime = (int64_t)(1 * NSEC_PER_SEC);
    //允許誤差時間租冠,設(shè)置為0即不允許有誤差
    uint64_t errorTime = 0;
    //按照上面的參數(shù)設(shè)置定時器
    dispatch_source_set_timer(self.gcdTimer, startTime, intervalTime, errorTime);
    //設(shè)置定時器的回調(diào)
    dispatch_source_set_event_handler(self.gcdTimer, ^{
        NSLog(@"GCD定時器調(diào)用");
    });
    //啟動定時器
    dispatch_resume(self.gcdTimer);

啟動定時器鹏倘,然后返回控制器,打印結(jié)果如下

2020-03-03 17:24:33.348304+0800 Test[57422:3669949] 當前時間
2020-03-03 17:24:35.348971+0800 Test[57422:3669949] GCD定時器調(diào)用,當前線程<NSThread: 0x600000cc4080>{number = 1, name = main}
2020-03-03 17:24:36.348850+0800 Test[57422:3669949] GCD定時器調(diào)用,當前線程<NSThread: 0x600000cc4080>{number = 1, name = main}
2020-03-03 17:24:37.303353+0800 Test[57422:3669949] 控制器被銷毀

由打印結(jié)果可以知道GCD的定時器不會引起循環(huán)引用顽爹。
暫停GCD定時器:

dispatch_suspend(self.gcdTimer);

取消GCD定時器:

dispatch_cancel(self.gcdTimer);

GCD定時器暫停之后仍然可以繼續(xù)執(zhí)行纤泵,NSTimer則不可以,NSTimer只能直接銷毀镜粤,需要再次啟動則需要重建創(chuàng)建NSTimer定時器捏题。
GCD定時器調(diào)用了"dispatch_cancel"之后則無法繼續(xù)執(zhí)行,通過打印調(diào)用“dispatch_cancel”之前和之后gcdTimer對象肉渴,可以發(fā)現(xiàn)之后對象中會標識出“cancelled”公荧。
注意點:
dispatch_suspend 狀態(tài)下無法釋放
如果調(diào)用 dispatch_suspend 后 timer 是無法被釋放的。一般情況下會發(fā)生崩潰并報“EXC_BAD_INSTRUCTION”錯誤同规,看下 GCD 源碼dispatch source release 的時候判斷了當前是否是在暫停狀態(tài)循狰。
所以,dispatch_suspend 狀態(tài)下直接釋放當前控制器或者釋放定時器券勺,會導(dǎo)致定時器崩潰绪钥。
并且初始狀態(tài)(未調(diào)用dispatch_resume)、掛起狀態(tài)关炼,都不能直接調(diào)用dispatch_source_cancel(timer)程腹,調(diào)用就會導(dǎo)致app閃退。
建議一:盡量不使用dispatch_suspend儒拂,在dealloc方法中跪楞,在dispatch_resume狀態(tài)下直接使用dispatch_source_cancel來取消定時器缀去。
建議二:使用懶加載創(chuàng)建定時器,并且記錄當timer 處于dispatch_suspend的狀態(tài)甸祭。這些時候缕碎,只要在 調(diào)用dealloc 時判斷下,已經(jīng)調(diào)用過 dispatch_suspend 則再調(diào)用下 dispatch_resume后再cancel池户,然后再釋放timer咏雌。
參考:iOS中如何正確釋放GCD定時器(dispatch_source_t)以及防止Crash?

3. CADisplayLink定時器

CADisplayLink是基于屏幕刷新的周期校焦,所以其一般很準時婶溯,每秒刷新60次粘都。其本質(zhì)也是通過RunLoop安皱,所以當RunLoop選擇其他模式或被耗時操作過多時想虎,仍舊會造成延遲。NSTimer中的循環(huán)引用問題他也存在耸成。
使用步驟:

//創(chuàng)建接受定時器回調(diào)的對象
    YYTimerResponse *timeresponse = [[YYTimerResponse alloc] init];
    // 創(chuàng)建CADisplayLink
    self.displayLink = [CADisplayLink displayLinkWithTarget:timeresponse selector:@selector(timered)];
    //設(shè)置定時器周期报亩,這個屬性即將被廢棄, 在iOS10新增了“preferredFramesPerSecond”代替他
//    self.displayLink.frameInterval = 60;
    self.displayLink.preferredFramesPerSecond = 1;
    // 添加至RunLoop中
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

使用“frameInterval”屬性設(shè)置定時器間隔時井氢,因為屏幕一秒鐘刷新60次弦追,所以設(shè)置為60,表示一秒鐘調(diào)用一次花竞。
使用“preferredFramesPerSecond”時劲件,設(shè)置的就是幾秒鐘刷新一次,該屬性iOS10.0后才能用约急。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末零远,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子厌蔽,更是在濱河造成了極大的恐慌牵辣,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躺枕,死亡現(xiàn)場離奇詭異服猪,居然都是意外死亡供填,警方通過查閱死者的電腦和手機拐云,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來近她,“玉大人叉瘩,你說我怎么就攤上這事≌成樱” “怎么了薇缅?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵危彩,是天一觀的道長。 經(jīng)常有香客問我泳桦,道長汤徽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任灸撰,我火速辦了婚禮谒府,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浮毯。我一直安慰自己完疫,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布债蓝。 她就那樣靜靜地躺著壳鹤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪饰迹。 梳的紋絲不亂的頭發(fā)上芳誓,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音蹦锋,去河邊找鬼兆沙。 笑死,一個胖子當著我的面吹牛莉掂,可吹牛的內(nèi)容都是我干的葛圃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼憎妙,長吁一口氣:“原來是場噩夢啊……” “哼库正!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起厘唾,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤褥符,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后抚垃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喷楣,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年鹤树,在試婚紗的時候發(fā)現(xiàn)自己被綠了铣焊。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡罕伯,死狀恐怖曲伊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情追他,我是刑警寧澤坟募,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布岛蚤,位于F島的核電站,受9級特大地震影響懈糯,放射性物質(zhì)發(fā)生泄漏涤妒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一赚哗、第九天 我趴在偏房一處隱蔽的房頂上張望届腐。 院中可真熱鬧,春花似錦蜂奸、人聲如沸犁苏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽围详。三九已至,卻和暖如春祖屏,著一層夾襖步出監(jiān)牢的瞬間助赞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工袁勺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雹食,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓期丰,卻偏偏與公主長得像群叶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钝荡,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

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