AOP實戰(zhàn)-IOS

一惧所、AOP簡介

  • AOP: Aspect Oriented Programming 面向切面編程与斤。

  • OOP:Object Oriented Programming 面向對象編程.

面向切面編程(也叫面向方面):Aspect Oriented Programming(AOP),是目前軟件開發(fā)中的一個熱點溉箕。利用AOP可以對業(yè)務邏輯的各個部分進行隔離壹若,從而使得業(yè)務邏輯各部分之間的耦合度降低晌姚,提高程序的可重用性沪曙,同時提高了開發(fā)的效率邑蒋。

AOP是OOP的延續(xù)姓蜂,相比傳統的OOP來說,OOP的特點在于它可以很好的將系統橫向分為很多個模塊(比如通訊錄模塊医吊,聊天模塊钱慢,發(fā)現模塊),每個子模塊可以橫向的衍生出更多的模塊卿堂,用于更好的區(qū)分業(yè)務邏輯束莫。而AOP其實相當于是縱向的分割系統模塊,將每個模塊里的公共部分提取出來(即那些與業(yè)務邏輯不相關的部分草描,如日志览绿,用戶行為等等),與業(yè)務邏輯相分離開來穗慕,從而降低代碼的耦合度饿敲。

AOP是可以通過預編譯方式和運行期動態(tài)代理實現在不修改源代碼的情況下給程序動態(tài)統一添加功能的一種技術。設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,提高代碼的靈活性和可擴展性逛绵,AOP可以說也是這種目標的一種實現怀各。

注意:AOP不是一種技術倔韭,實際上是編程思想。凡是符合AOP思想的技術瓢对,都可以看成是AOP的實現

二寿酌、為什么要用AOP

AOP的優(yōu)勢:
  • 減少切面業(yè)務的開發(fā)量,“一次開發(fā)終生使用”沥曹,比如日志
  • 減少代碼耦合份名,方便復用碟联。切面業(yè)務的代碼可以獨立出來妓美,方便其他應用使用
  • 提高代碼review的質量,比如我可以規(guī)定某些類的某些方法才用特定的命名規(guī)范鲤孵,這樣review的時候就可以發(fā)現一些問題
AOP的弊端:
  • 濫用AOP容易在多人集成開發(fā)時踩坑壶栋,比如自己的代碼會被他人的切片處理所“劫持”

三、Spring里的AOP

  • Spring的AOP是較典型的AOP使用普监,這里單獨介紹一下
(1)通知(增強)Advice

通知定義了切面是什么以及何時使用贵试,應該應用在某個方法被調用之前?之后凯正?還是拋出異常時毙玻?等等。

(2)連接點 Join point

連接點是在應用執(zhí)行過程中能夠插入切面的一個點廊散。這個點可以是調用方法時桑滩,拋出異常時,甚至修改一個字段時允睹。切面代碼可以利用這些點插入到應用的正常流程中运准,并添加新的行為。

(3)切點 Pointcut

切點有助于縮小切面所通知的連接點的范圍缭受。如果說通知定義了切面的“什么”和“何時”的話胁澳,那么切點就定義了“何處”,切點會匹配通知所要織入的一個或多個連接點米者,一般常用正則表達式定義所匹配的類和方法名稱來指定這些切點韭畸。

(4)切面 Aspect

切面是通知和切點的結合。通知和切點定義了切面的全部內容——它是什么蔓搞,在何時何處完成其功能陆盘。

(5)引入 Introduction

引入允許我們向現有的類添加新方法或屬性,從而無需修改這些現有類的情況下败明,讓他們具有新的行為和狀態(tài)隘马。

(6)織入 Weaving

在過去我常常把織入與引入的概念混淆,我是這樣來辨別的妻顶,“引入”我把它看做是一個定義酸员,也就是一個名詞蜒车,而“織入”我把它看做是一個動作,一個動詞幔嗦,也就是切面在指定的連接點被織入到目標對象中酿愧。

Spring AOP的簡單示例

public interface CustomerDao {
    public void add();
    public void update();
    public void delete();
    public void find();
}


public class CustomerDaoImpl implements CustomerDao {
    public void add() {
        System.out.println("添加客戶");
    }
    public void update() {
        System.out.println("修改客戶");
    }
    public void delete() {
        System.out.println("刪除客戶");
    }
    public void find() {
        System.out.println("查詢客戶");
    }
}


public class MyBeforeAdvice implements MethodBeforeAdvice{
    /**
     * method:執(zhí)行的方法
     * args:參數
     * target:目標對象
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置增強...");
    }
}



<!-- 不帶有切點的切面 -->
<!-- 定義目標對象 -->
<bean id="customerDao" class="cn.yzu.spring3.demo3.CustomerDaoImpl"></bean>   
<!-- 定義增強 -->
<bean id="beforeAdvice" class="cn.yzu.spring3.demo3.MyBeforeAdvice"></bean>
<!-- Spring支持配置生成代理: -->
<bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  <!-- 設置目標對象 -->
  <property name="target" ref="customerDao"/>
  <!-- 設置實現的接口 ,value中寫接口的全路徑 -->
    <property name="proxyInterfaces" value="cn.yzu.spring3.demo3.CustomerDao"/>
    <!-- 需要使用value:要的名稱 -->
    <property name="interceptorNames" value="beforeAdvice"/>
    <!-- 強制使用CGLIB代理 -->
    <property name="optimize" value="true"></property>
</bean>



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest3 {
    @Autowired
    //不可注入@Qualifier("customerDao"),必須注入代理對象.
    @Qualifier("customerDaoProxy")
    private CustomerDao customerDao;  
    @Test
    public void demo1(){
        customerDao.add();
        customerDao.update();
        customerDao.delete();
        customerDao.find();
        /**
         * 輸出:
         *     前置增強...
              添加客戶
              前置增強...
              修改客戶
              前置增強...
              刪除客戶
              前置增強...
              查詢客戶
         */
    }
}

四、 iOS AOP實戰(zhàn)

實例:股票app全局換膚系統

需求背景:

產品希望整個app能夠具有多個風格的UI(如:黑色經典邀泉,白色簡約等)嬉挡,并且在不同的入口處(首頁,側邊欄汇恤,我的庞钢,分時頁面等)提供風格選擇按鍵提供用戶自由選擇app UI風格

需求分析:

實際將需求分解后,我們發(fā)現涉及到的模塊包括:首頁因谎,行情基括,資訊,交易财岔,個人中心等风皿,預估修改頁面數量超過30個以上,修改控件數量超過200個以上

初期實現方式-廣播模式:
  • 編寫風格皮膚模版(定義不同風格的顏色匠璧,圖片)
  • 編寫風格皮膚中心(廣播發(fā)起者)
  • 編寫不同入口觸發(fā)風格切換按鍵以及事件綁定
  • 修改涉及到風格切換的所有頁面(廣播接收者)桐款,用于接收風格皮膚中心發(fā)起換膚廣播
實現難點:
  • 涉及到換膚的頁面控件數量龐大
  • 必須將其所有改寫為廣播模式的接受者(注冊通知接受,處理通知回調夷恍,注銷通知接受)
  • 換膚控件以及子控件頁面都需在全局顯式定義魔眨,方便在通知處理中引用,對代碼污染巨大

view監(jiān)聽/移除:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
  
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vcMsgThemeChange:) name:kThemeChangeNotification object:nil];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kThemeChangeNotification object:nil];
    [super dealloc];
}

ViewController監(jiān)聽/移除:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
   
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vcMsgThemeChange:) name:kThemeChangeNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vcStatusBarFrameChange:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];

    }
    
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kThemeChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
    [super dealloc];
}

接受通知處理:

- (void)vcMsgThemeChange:(NSNotification *)notification
{
    [super vcMsgThemeChange:notification];
    
    CMSegmentControl *segment           = self.segmentView;
    segment.backgroundColor             = ThemeColorWithID(420);
    segment.selectionIndicatorColor     = ThemeColorWithID(427);
    segment.textColor                   = ThemeColorWithID(429);
    segment.selectedTextColor           = ThemeColorWithID(430);
    [segment setNeedsDisplay];
    
    _leftDateLabel.textColor            = CLRINFOTEXT;
    _rightDateLabel.textColor           = CLRINFOTEXT;
    
    [_exRightButton setTitleColor:ThemeColorWithID(40306) forState:UIControlStateNormal];
    _exRightButton.backgroundColor      = ThemeColorWithID(40514);
    
    [_technicalButton setTitleColor:ThemeColorWithID(40306) forState:UIControlStateNormal];
    _technicalButton.backgroundColor    = ThemeColorWithID(40514);

    [_horizonCursor setNeedsDisplay];
    [_verticalCursor setNeedsDisplay];
    
    _midFloatPanel.backgroundColor      = ThemeColorWithID(425);
    [_floatPanel updateColors];
    
    _volMaPanel.backgroundColor         = ThemeColorWithID(40530);
    
    self.costDistribution.backgroundColor = ThemeColorWithID(40610);
    self.costDistribution.layer.borderColor = ThemeColorWithID(40611).CGColor;
    [self.costDistribution redraw];
    
    [_klineView updateColors];
    
    [_prevPage setImage:[UIImage theme_imageNamed:@"move_prev"] forState:UIControlStateNormal];
    [_prevPage setImage:[UIImage theme_imageNamed:@"move_prev_highlight"] forState:UIControlStateHighlighted];
    
    [_nextPage setImage:[UIImage theme_imageNamed:@"move_next"] forState:UIControlStateNormal];
    [_nextPage setImage:[UIImage theme_imageNamed:@"move_next_highlight"] forState:UIControlStateHighlighted];
    
    self.tecCycle.textColor             = CLRINFOTEXT;
   [_horizonBtn setBackgroundColor:ThemeColorWithID(40324)];
    [_horizonBtn setTitleColor:ThemeColorWithID(40325) forState:UIControlStateNormal];
}
AOP方式實現:
  • 編寫風格皮膚模版(定義不同風格的顏色裁厅,圖片)
  • 編寫AOP風格皮膚中心
  • 編寫不同入口觸發(fā)風格切換按鍵以及事件綁定
  • 改寫控件顏色冰沙,圖片設置方法名和參數
對比廣播模式:
  • 無需在頁面中編寫廣播模式注冊,注銷执虹,接收代碼
  • 無需全局顯式定義換膚控件
  • 代碼改動量小的多
  • 代碼污染性拓挥,侵入小

UI修改-背景顏色

UIView *view = [[[UIView alloc] initWithFrame:self.frame] autorelease];
 [view setThemeBackgroundColor:353];

UI修改-文字顏色

UILabel *label = [[[UILabel alloc]initWithFrame:self.bounds]autorelease];
[label setThemeTextColor:521];

UI修改-圖片

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)]; 
[imageView setThemeImage:20];
具體實現部分代碼:

DZHUIThemeManger+Passthrough.h

#import "DZHThemeDefine.h"
@interface DZHUIThemeManger (Passthrough)

-(void)bind:(NSObject *)themeObject colorChange:(dispatch_block_t)colorChange;

-(void)notifyColorChange;
@end

DZHUIThemeManger+Passthrough.m

#import "DZHUIThemeManger+Passthrough.h"
#import <libkern/OSAtomic.h>
#import "NSObject+CMDeallocating.h"

@interface NSObject (ThemeBind)
@property(nonatomic,assign)BOOL isBind;
@end

@implementation NSObject (ThemeBind)

-(void)setIsBind:(BOOL)isBind
{
    objc_setAssociatedObject(self, @selector(isBind), @(isBind), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(BOOL)isBind
{
    return [objc_getAssociatedObject(self, @selector(isBind)) boolValue];
}

@end

@interface ThemePassthrough : NSObject
@property(nonatomic,assign)NSObject *orgin;
@property(nonatomic,retain)NSMutableArray *colorChanges;
@property(nonatomic,readonly)NSString *description;

-(instancetype)initWithOrgin:(NSObject *)orgin colorChange:(dispatch_block_t)colorChange;

-(void)execute;

-(void)searial:(dispatch_block_t)colorChange;
@end

@implementation ThemePassthrough
@dynamic description;
-(instancetype)initWithOrgin:(NSObject *)orgin colorChange:(dispatch_block_t)colorChange
{
    self = [super init];
    if (self) {
        self.orgin = orgin;
        self.orgin.isBind = YES;
        dispatch_block_t innerBlock = [[colorChange copy]autorelease];
        self.colorChanges = [[[NSMutableArray alloc]initWithObjects:innerBlock,nil]autorelease];
    }
    return self;
}

- (NSString *)description {
    return [[[NSString alloc] initWithFormat:@"<%@: %p>", self.class, self]autorelease];
}

-(void)dealloc
{
    self.colorChanges = nil;
    [super dealloc];
}

-(void)searial:(dispatch_block_t)colorChange;
{
    @synchronized(self.colorChanges){
        if (!self.orgin.themeColoring) {
            [self.colorChanges removeAllObjects];
        }
        dispatch_block_t innerBlock = [[colorChange copy]autorelease];
        [self.colorChanges addObject:innerBlock];
    }
}

-(void)execute
{
    NSEnumerator *enumerator =[self.colorChanges objectEnumerator];
    dispatch_block_t colorChange;
    while (colorChange = [enumerator nextObject])
    {
        colorChange();
    }
}
@end

@implementation DZHUIThemeManger (Passthrough)

OSSpinLock _spinLock;

static NSMutableArray *passthoughs() {
    static dispatch_once_t onceToken;
    static NSMutableArray *passthoughs = nil;
    dispatch_once(&onceToken, ^{
        passthoughs = [[NSMutableArray alloc] init];
    });
    
    return passthoughs;
}

-(void)bind:(NSObject *)themeObject colorChange:(dispatch_block_t)colorChange
{
    if (themeObject.isBind) {
        [self change:themeObject colorChange:colorChange];
        return;
    }
    
    OSSpinLockLock(&_spinLock);
    {
        ThemePassthrough *passthrough = [[[ThemePassthrough alloc]initWithOrgin:themeObject colorChange:colorChange]autorelease];
        [passthoughs() addObject:passthrough];
        CMLogDebug(@"passthoughs() [ADD]  count is :%ld",(long)passthoughs().count);
        [themeObject swizzleDeallocInsertBlockAction:^(id objSelf) {
            OSSpinLockLock(&_spinLock);
            {
                NSUInteger index = [passthoughs() indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (ThemePassthrough *obj, NSUInteger index, BOOL *stop) {
                    return obj.orgin == objSelf;
                }];
                
                if (index != NSNotFound) {
                    [passthoughs() removeObjectAtIndex:index];
                    CMLogDebug(@"passthoughs() [REMOVE]  count is :%ld",(long)passthoughs().count);
                }
            }
            OSSpinLockUnlock(&_spinLock);
        }];

    }
    OSSpinLockUnlock(&_spinLock);
    
}

-(void)change:(NSObject *)themeObject colorChange:(dispatch_block_t)colorChange
{
    OSSpinLockLock(&_spinLock);
    {
        NSUInteger index = [passthoughs() indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (ThemePassthrough *obj, NSUInteger index, BOOL *stop) {
            return obj.orgin == themeObject;
        }];
        
        ThemePassthrough *passthrough = passthoughs()[index];
        [passthrough searial:colorChange];
    }
    OSSpinLockUnlock(&_spinLock);
}

-(void)notifyColorChange
{
    OSSpinLockLock(&_spinLock);
    {
        for (ThemePassthrough *passthrough in passthoughs()) {
            @autoreleasepool {
                [passthrough execute];
            }
        }
    }
    OSSpinLockUnlock(&_spinLock);
}

@end

UIView+ThemeAddition.h

#import <UIKit/UIKit.h>
typedef void(^themeColorBlock)(id obj ,BOOL isThemeChange);

@interface UIView (ThemeAddition)
-(void)setThemeBackgroundColor:(NSUInteger)tid;
@end

@interface UIButton (ThemeAddition)
-(void)setThemeTitleColor:(NSUInteger)tid forState:(UIControlState)state;
@end


@interface UILabel (ThemeAddition)
-(void)setThemeTextColor:(NSUInteger)tid;
@end


@interface CALayer (ThemeAddition)
-(void)setThemeBorderColor:(NSUInteger)tid;
@end


@interface NSObject (ThemeAddition)
@property(nonatomic,readonly)BOOL themeColoring;
-(void)beginThemeColor;
-(void)endThemeColor;
-(void)themeColorGroup:(void(^)(id obj))group;
-(void)themeColorGroupEx:(themeColorBlock)group;
@end

UIView+ThemeAddition.m

#import "UIView+ThemeAddition.h"
#import "DZHThemeDefine.h"
#import "DZHUIThemeManger+Passthrough.h"

@implementation UIView (ThemeAddition)

-(void)setThemeBackgroundColor:(NSUInteger)tid
{
#ifdef DEBUG
//    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    __block typeof(self) weak = self;
    dispatch_block_t colorChange = ^
    {
#ifdef DEBUG
//       CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
       weak.backgroundColor = ThemeColorWithID(tid);
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:colorChange];
    colorChange();
}
@end


@implementation UIButton (ThemeAddition)

-(void)setThemeTitleColor:(NSUInteger)tid forState:(UIControlState)state;
{
#ifdef DEBUG
//    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    __block typeof(self) weak = self;
    dispatch_block_t colorChange = ^
    {
#ifdef DEBUG
//        CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
        [weak setTitleColor:ThemeColorWithID(tid) forState:state];
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:colorChange];
    colorChange();
}

@end

@implementation UILabel (ThemeAddition)

-(void)setThemeTextColor:(NSUInteger)tid
{
#ifdef DEBUG
//    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    __block typeof(self) weak = self;
    dispatch_block_t colorChange = ^
    {
#ifdef DEBUG
//        CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
        weak.textColor = ThemeColorWithID(tid);
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:colorChange];
    colorChange();
}
@end


@implementation CALayer (ThemeAddition)

-(void)setThemeBorderColor:(NSUInteger)tid;
{
#ifdef DEBUG
//    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    __block typeof(self) weak = self;
    dispatch_block_t colorChange = ^
    {
#ifdef DEBUG
//        CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
        weak.borderColor = ThemeColorWithID(tid).CGColor;
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:colorChange];
    colorChange();
}
@end


@implementation NSObject (ThemeAddition)
@dynamic themeColoring;
-(void)setThemeColoring:(BOOL)themeColoring
{
    objc_setAssociatedObject(self, @selector(themeColoring), @(themeColoring), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(BOOL)themeColoring
{
    return [objc_getAssociatedObject(self, @selector(themeColoring))boolValue];
}

-(void)beginThemeColor
{
    self.themeColoring = YES;
}

-(void)endThemeColor
{
    self.themeColoring = NO;
}

-(void)themeColorGroup:(void(^)(id obj))group;
{
#ifdef DEBUG
//    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    self.themeColoring = NO;
    __block typeof(self) weak = self;
    dispatch_block_t b = ^
    {
#ifdef DEBUG
//        CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
        group(weak);
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:b];
    b();
}

-(void)themeColorGroupEx:(themeColorBlock)group
{
#ifdef DEBUG
    //    NSArray *debugErrorCallStackSymbols = [NSThread callStackSymbols];
#endif
    self.themeColoring = NO;
    __block typeof(self) weak = self;
    dispatch_block_t b = ^
    {
#ifdef DEBUG
        //        CMLogDebug([debugErrorCallStackSymbols componentsJoinedByString:@"\r\n"]);
#endif
        group(weak,YES);
    };
    [[DZHUIThemeManger sharedInstance]bind:self colorChange:b];
    group(weak,NO);
}
@end

實現原理:
  • 封裝顏色,圖片設置操作為閉包(block)并在換膚中心持久化
  • 換膚時從換膚中心遍歷換膚操作閉包袋励,并執(zhí)行
  • 利用運行時(runtime)將控件的銷毀狀態(tài)和換膚操作閉包進行綁定
  • 擴展控件UI方法用以支持換膚

總結

  • AOP是一種思想侥啤,也是運用在不同程序架構中的解決方案
  • 目的:在不改變已封裝對象的結構,甚至是不改變代碼的前提下茬故,將可復用可封裝的邏輯插入其中盖灸,達到降低了模塊間的耦合度,同時提高系統的可維護性效果磺芭。
  • 實現策略:大致分為預編譯和運行時2種赁炎。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钾腺,隨后出現的幾起案子徙垫,更是在濱河造成了極大的恐慌讥裤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姻报,死亡現場離奇詭異己英,居然都是意外死亡,警方通過查閱死者的電腦和手機吴旋,發(fā)現死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門损肛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荣瑟,你說我怎么就攤上這事治拿。” “怎么了褂傀?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵忍啤,是天一觀的道長加勤。 經常有香客問我仙辟,道長,這世上最難降的妖魔是什么鳄梅? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任叠国,我火速辦了婚禮,結果婚禮上戴尸,老公的妹妹穿的比我還像新娘粟焊。我一直安慰自己,他們只是感情好孙蒙,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布项棠。 她就那樣靜靜地躺著,像睡著了一般挎峦。 火紅的嫁衣襯著肌膚如雪香追。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天坦胶,我揣著相機與錄音透典,去河邊找鬼。 笑死顿苇,一個胖子當著我的面吹牛峭咒,可吹牛的內容都是我干的。 我是一名探鬼主播纪岁,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼凑队,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了幔翰?” 一聲冷哼從身側響起漩氨,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤短条,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后才菠,有當地人在樹林里發(fā)現了一具尸體茸时,經...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年赋访,在試婚紗的時候發(fā)現自己被綠了可都。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚓耽,死狀恐怖渠牲,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情步悠,我是刑警寧澤签杈,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站鼎兽,受9級特大地震影響答姥,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谚咬,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一鹦付、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧择卦,春花似錦敲长、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尚辑,卻和暖如春辑鲤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背腌巾。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工遂填, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人澈蝙。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓吓坚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灯荧。 傳聞我的和親對象是個殘疾皇子礁击,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,498評論 25 707
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,693評論 2 59
  • 整天哆窿,我們游蕩在 大街小巷链烈,山林和河邊 哦,你知道 最美好的日子總是被虛度的 一輩子太久 三十年挚躯,四十年强衡,或者 三...
    af08baae2793閱讀 307評論 1 7
  • 英國藝術家David Poxon寫實水彩畫,David Poxon的作品码荔,尤愛描繪銹跡斑斑的殘舊金屬機械和木頭漩勤,豐...
    AmeliaL閱讀 797評論 0 1
  • 弟弟凌晨1點在微信朋友圈上發(fā)了一個信息:“生活再艱難都要記得給自己一個掌聲∷踅粒” 我相信越败,這是他的心聲。家里三個孩子...
    葉子的文藝麥田閱讀 1,020評論 1 1