DWCollectionView

github傳送門:https://github.com/DawnWdf/DWCollectionView

支持Carthage安裝育特,請在Cartfile中填寫

github "DawnWdf/DWCollectionView"

支持cocoaPods安裝

pod "DWCollectionView"
為什么封裝CollectionView
  • 項目中用到collectionView的地方很多,每一個VC里面都需要至少兩個代理方法,如果碰到頁面稍微復雜一點强胰,代理方法寫的更多毅该。當有N個頁面都需要寫相同的N個代理方法的時候须妻。菇篡。。波闹。酝豪。。

  • 頁面需要多個collectionView精堕,需要在多個代理方法中判斷當前使用的collectionView是哪個

  • 一個collectionView需要使用很多個不同樣子的cell孵淘。定義了N個cell,于是在每一個代理方法里面都有一個if-else來各種判斷歹篓。

    當然瘫证,這個可以通過其他的方法來規(guī)避部分if-else判斷。比如說:當ModelA對應CellA,ModelB對應CellB……

    • 讓所有的Model都遵循一個協(xié)議ModelPropocol庄撮。讓所有的cell都繼承自一個基類BaseCell背捌。
    • ModelPropocol有一個方法cellNameFor,根據(jù)不用的ID來返回對應的cell的類名
    • 在cellForItemAtIndexPath代理方法里面根據(jù)cell的類名創(chuàng)建cell洞斯,并執(zhí)行數(shù)據(jù)綁定的操作毡庆。

    但是這個做法也有很多弊端,比如

    • 在使用例如didSelectItemAtIndexPath方法時依然要if-else烙如,使用numberOfItemsInSection方法時也依然要判斷么抗。
    • 同時也需要定義很多個id用來在相同model的情況下區(qū)分不同的cell。
    • 業(yè)務要是再復雜一點亚铁,感覺就像是將每一個代理方法里面的if-else分發(fā)到了model中一樣蝇刀。model過于沉重,不僅保存了數(shù)據(jù)刀闷,還保存了對應的UI熊泵,還需要針對每一個代理方法做多余的操作仰迁。感覺已經(jīng)超出了重量級model該做的事情甸昏。
    • 我們希望我們的model或者cell可以復用,當我們希望某一個model可以對接不同頁面不同cell的時候徐许。施蜜。。雌隅。翻默。缸沃。又或者希望我們的model和cell是可插拔式的。
  • 有的項目中會有一些比較復雜和靈活的頁面修械。比如趾牧,整個頁面都是可以自由配置的。需要根據(jù)接口返回的數(shù)據(jù)來進行排版布局肯污。像是我現(xiàn)在做的項目翘单,除了要根據(jù)返回的數(shù)據(jù)來布局模塊的順序,還要求配置頁面上兩個cell之間是否有一個10像素的間距蹦渣,配置某一個cell上面或者下面是否有一個1像素的分割線哄芜。如果接口返回的數(shù)據(jù)結(jié)構(gòu)正好可以對接你的UI柬唯,那真是可喜可賀,如果無法對接失晴,需要自己判斷和組裝然后再渲染視圖。等你渲染了視圖拘央,接口要是升級或者字段調(diào)整师坎。胯陋。。袱箱。遏乔。发笔。萬一架構(gòu)的時候腦抽,或者寫代碼的時候犯二捻激,那真是“完美”前计。當然如果架構(gòu)夠好,這也是沒什么的丈屹。

我相信一定會有人做過類似的項目旺垒,踩過類似的坑的,對很多類似的骇钦、機械似的代碼表示厭煩竞漾。于是我封裝了collectionView畴蹭。當然我不會告訴你,同組的一個大神封裝了一個tableview讓我受益匪淺繁扎,燃起了自己也寫一個的欲望糊闽。這充分說明了右犹,跟著大神走,有肉吃盼忌。

封裝后可以渲染哪種頁面

  • 普通列表


    Simulator Screen Shot - iPhone 8 Plus - 2017-11-24 at 18.01.49.png
  • 用戶中心


    Simulator Screen Shot - iPhone 8 Plus - 2017-11-27 at 11.13.51.png
  • 瀑布流(配合使用flowLayout)
    Simulator Screen Shot - iPhone 8 Plus - 2017-11-27 at 11.34.21.png
  • 還有多種多樣列表

Simulator Screen Shot - iPhone 8 Plus - 2017-11-27 at 11.39.06.png
Simulator Screen Shot - iPhone 8 Plus - 2017-11-27 at 11.39.14.png

只要配置好model與cell的對應關系,只要管理數(shù)據(jù)結(jié)構(gòu)就可以渲染視圖了跨嘉。

代碼如何實現(xiàn)

  1. 創(chuàng)建collection
    就像創(chuàng)建一個普通UICollectionView一樣祠乃,除了把類名換成DWCollectionView以外兑燥,沒有其他操作。而且在不聲明UICollectionViewLayout的情況下寺庄,默認添加上去斗塘,免得崩潰亮靴。
    DWCollectionView *cv= [[DWCollectionView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)) collectionViewLayout:layout];
    cv.backgroundColor = [UIColor whiteColor];
    cv.delegate = self;
    [self.view addSubview:cv];
  1. 配置model和cell的關系
  • 創(chuàng)建collectionView的時候我并沒有配置dataSource = self;也沒有給collectionView注冊任何cell或者reuseview茧吊。
  • 然而我們的collectionView需要配置數(shù)據(jù)源搓侄,并必須實現(xiàn)協(xié)議UICollectionViewDataSource中兩個方法。
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
  • 通常情況下cellForItemAtIndexPath的方法里面會寫model和cell的對應關系芯侥,通過數(shù)據(jù)源和IndexPath找到model柱查,再通過model去創(chuàng)建或者復用cell云石,然后給cell進行數(shù)據(jù)綁定汹忠。這個方法大概是所有代理方法中最重的一個。
  • 我封裝后的collectionView則將注冊和model&cell之間的綁定簡化了一下奖地。
    [self.collectionView registerViewAndModel:^(DWCollectionDelegateMaker *maker) {
        
        maker.registerCell([TeamInfoCell class],[TeamInfo class])
        .itemSize(^(NSIndexPath *indexPath, id data){
            return CGSizeMake(100, 140);
        })
        .adapter(^(UICollectionViewCell *cell, NSIndexPath *indexPath, id data){
            TeamInfoCell *newCell = (TeamInfoCell *)cell;
            newCell.showImage = YES;
            [newCell bindData:data];
        })
        .didSelect(^(NSIndexPath *indexPath, id data){
            NSLog(@"did select block : 如果vc中實現(xiàn)了didSelect的代理方法参歹,則在此block后執(zhí)行");
        });
 
    }];
  • 整體采用響應鏈式的編程方式犬庇。
    registerViewAndModel方法承擔了cellForItemAtIndexPath全部的工作侨嘀。
    maker.registerCell的工作是告訴collectionView將model和cell綁定咬腕,只要數(shù)據(jù)源中出現(xiàn)model,就用對應的cell去渲染視圖纽帖。
    maker. itemSize替代了- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
    maker. adapter中的block則返回了每一個cell和當前cell對應的具體的數(shù)據(jù)懊直,在這里我們可以進行數(shù)據(jù)綁定,將model中具體的內(nèi)容渲染到cell中雕崩。這樣就節(jié)省了通過數(shù)據(jù)源和Indexpath來找到對應model再去渲染的麻煩盼铁。

    這里的cell我都遵循了DWCollectionViewCellProtocol協(xié)議尝偎,實現(xiàn)了- (void)bindData:(id)data;方法冬念,以便在cell中做具體的綁定操作。

    maker.didSelect的方法則完全是代理方法- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;的替代醒陆。
    但是不是完全的替代刨摩,如果當前的VC中同時實現(xiàn)了這個代理方法世吨,那么block中的方法先執(zhí)行耘婚,然后執(zhí)行代理中的方法。
    到這里嚷闭,一個簡單的collectionView已經(jīng)搭建完畢胞锰。這里通過幾個block完成了注冊視圖和至少三個必備代理方法兢榨。
    我們再也不用滿VC去找每個代理方法然后做處理了。因為都在這了兼雄。
    類似的案怯,header&footer的方法一致嘲碱。

       //header
        maker.registerHeader([UserCenterHeaderCollectionReusableView class],[UserCenterHeaderModel class])
        .sizeConfiger(^(UICollectionViewLayout *layout,NSInteger section, id data){
            return CGSizeMake(screenW, 33);
        })
        .adapter(^(UICollectionReusableView *reusableView,NSIndexPath *indexPath, id data) {
            UserCenterHeaderCollectionReusableView *view = (UserCenterHeaderCollectionReusableView *)reusableView;
            [view bindData:data];
        });
        
        //footer
        maker.registerFooter([UICollectionReusableView class],[NSString class])
        .sizeConfiger(^(UICollectionViewLayout *layout,NSInteger section, id data){
            return CGSizeMake(screenW, 10);
        })
        .adapter(^(UICollectionReusableView *reusableView,NSIndexPath *indexPath, id data) {
            reusableView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.5];
        });
  • 給collectionView賦值麦锯。
    由于封裝后的collectionView是數(shù)據(jù)驅(qū)動視圖的扶欣,給collectionView賦值就變得很重要千扶。所以數(shù)據(jù)也進行了一次封裝澎羞。
    按照collectionView每一個section分為頭妆绞、尾和items將數(shù)據(jù)分為三個對應的部分

    @interface DWSection : NSObject <NSCoding>
    @property (nonatomic, strong) id headerData;
    @property (nonatomic, strong) id footerData;
    @property (nonatomic, strong) NSArray *items;
    @end
    

    items里面存的就是所有需要展示的,并且已經(jīng)注冊過的model株茶。
    [self.collectionView setData:data];
    data為一個數(shù)組启盛,里面的每一個元素都是DWSection的對象技羔。
    這樣做有一個好處就是堕阔,這個model很大的作用其實是脫離業(yè)務的超陆,針對視圖的model浦马。這樣如果接口數(shù)據(jù)結(jié)構(gòu)有變化晶默,而UI無變化航攒,只要將接口數(shù)據(jù)和model做對接就可以了漠畜。而且model可插拔憔狞,如果這個cell&model要移植到其他的項目或功能中,也只要在拼接數(shù)據(jù)的時候做點手腳就可以拍冠。舉個栗子:

    在做項目的時候庆杜,接口數(shù)據(jù)不能及時給出碟摆,就需要客戶端做一個假的數(shù)據(jù)焦履,我就根據(jù)接口文檔寫了dictionary來渲染cell嘉裤。但是當接入了接口,使用工程基本網(wǎng)絡框架后發(fā)現(xiàn)厢洞,它自動把返回的字典轉(zhuǎn)成了對應的業(yè)務相關model躺翻,里面一大堆跟UI無關的數(shù)據(jù)卫玖。于是我直接從業(yè)務model中抽出UI需要展示的屬性直接賦值給model&cell假瞬。

    我在實際項目中使用的時候,這個model大多數(shù)都有幾個相同的屬性

    @property (nonatomic, copy) NSString *title;//cell標題
    @property (nonatomic, copy) NSString *imageUrl;//圖片
    @property (nonatomic, copy) NSString *content;//內(nèi)容
    @property (nonatomic, copy) NSString *scheme;//跳轉(zhuǎn)URL
    

    主要說一下屬性scheme垄开。有一段時間router這個東西特別流行税肪,我想現(xiàn)在應該有很多項目也都有使用router益兄。而這個scheme就是為了router而存在的偏塞。我們的cell在點擊的時候大多要跳轉(zhuǎn)到一個二級頁面灸叼,有時需要傳遞一些參數(shù)庆捺,id/type什么的滔以。之前的做法則是在model中也聲明一個屬性ID,然后跳轉(zhuǎn)的時候傳值抵碟。
    這里我們可以在viewModel中做數(shù)據(jù)轉(zhuǎn)換的時候拟逮,就根據(jù)要求將scheme拼接好敦迄,將需要傳遞的參數(shù)都放在sheme中凭迹。這樣點擊cell進行頁面跳轉(zhuǎn)的時候可以統(tǒng)一使用scheme進行頁面跳轉(zhuǎn)嗅绸,很大程度上降低了耦合度鱼鸠。如果所有的model的scheme屬性都一樣的話,就更加快捷漆弄,我們都不用關心我們拿到的id類型的數(shù)據(jù)data到底是哪個model了撼唾,只要它實現(xiàn)了scheme就行倒谷。像這樣

    if ([data respondsToSelector:NSSelectorFromString(@"scheme")]) {
              SEL sel = NSSelectorFromString(@"scheme");
              IMP selImp = [data methodForSelector:sel];
              id(*func)(id,SEL) = (void *)selImp;
              id scheme = func(data,sel);
              [ARouter jumpWithScheme:scheme title:nil other:nil];
    }
    

到此渤愁,一個簡單的collectionView就全部完畢∨灯唬總結(jié)一下就三個步驟:

  1. 創(chuàng)建
  2. 綁定
  3. 添加數(shù)據(jù)源

其他的代理方法

我在封裝的時候收奔,希望對原有collectionView的侵入性最小坪哄。所以你會發(fā)現(xiàn)翩肌,只有上面提到的常用的代理方法是使用block的形式封裝在了一起禁悠。如果collectionView的功能比較多绷蹲,需要實現(xiàn)其他的代理方法祝钢,比如:- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath 拦英;還是需要自己在vc中寫好的疤估。
所以霎冯,如果對layout有特殊的要求沈撞,依然可以實現(xiàn)相應的代理方法缠俺。如:

#pragma mark - UICollectionViewDelegateFlowLayout

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(10, 10, 10, 10);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 10;
}

或者在創(chuàng)建的時候直接使用

 UICollectionViewFlowLayout *sysLayout = [[UICollectionViewFlowLayout alloc] init];
 sysLayout.estimatedItemSize = CGSizeMake(100, 150);
 sysLayout.minimumLineSpacing = 50;

這些都是使用UICollectionView標準的方式壹士,不贅述躏救。

題外話:DWFlowLayout(自定義布局-瀑布流)盒使,不在封裝范圍內(nèi)忠怖。

缺憾

為了能更好的封裝代理方法抄瑟,我將代理做了重定向皮假。所以惹资,collectionView的代理在執(zhí)行的時候用的并不是聲明時指向的代理VC航闺,而是我自己的代理類DWCollectionDelegate潦刃。我只是在DWCollectionDelegate記錄了VC乖杠,并在對應的方法中調(diào)用了一次VC的方法胧洒。
然而collectionView遵循的協(xié)議有四個:

  • UICollectionViewDataSource
  • UICollectionViewDelegate
  • UICollectionViewDelegateFlowLayout
  • UIScrollViewDelegate

如果把所有的協(xié)議的代理方法都寫出來,那就是個天文數(shù)字菲饼。
所以我將不常用的代理方法使用runtime的方法做了轉(zhuǎn)換肾砂。
具體的代碼如下:

for (int i = 0; i < protocolMethodCount; i++) {
                    struct objc_method_description protocolObject = protocolDes[i];
                    
                    SEL selector = protocolObject.name;
                    //originalDelegate是否實現(xiàn)此方法
                    BOOL isOriginalResponse = class_respondsToSelector(original , selector);
                   if (isOriginalResponse) {
                        Method originalMethod = class_getInstanceMethod(original, selector);
                        class_replaceMethod(aclass, selector, class_getMethodImplementation(original, selector), method_getTypeEncoding(originalMethod));
                    }
                }

注釋中的originalDelegate代表的就是聲明時設置的代理VC『暝茫‘當前類’代表的就是DWCollectionDelegate通今。從代碼中可以看出我實際上是將兩個類的代理方法的imp互換了。所以就會出現(xiàn)一個問題肛根,例如代理方法-(void)scrollViewDidScroll:(UIScrollView *)scrollView在當前類中不存在辫塌,但是在originalDelegate中存在了,替換了imp后派哲,在scrollViewDidScroll方法中的self就成了DWCollectionDelegate。所以這樣的代理方法中就要判斷一下self是哪個類芭届。同時储矩,由于DWCollectionDelegate已經(jīng)添加了這個代理方法,如果在其他的VC中不需要執(zhí)行這個代理方法褂乍,它會去實現(xiàn)過的方法中找持隧,所以也需要判斷delegate.originalDelegate是否為你需要的vc。遜斃了L悠B挪Α!low貨H焓怠呀狼!

UserCenterViewController.m中實現(xiàn)代理方法

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGPoint offset = scrollView.contentOffset;
    if ([self isKindOfClass:[DWCollectionDelegate class]]) {
        DWCollectionDelegate *delegate = (DWCollectionDelegate *)self;
        id original = delegate.originalDelegate;
        if ([original isKindOfClass:[UserCenterViewController class]]) {
            UserCenterViewController *vc = (UserCenterViewController *)original;
            [vc updateUserInforView:scrollView];
            [vc updateNav:offset];
        }

    }else if([self isKindOfClass:[UserCenterViewController class]]){
        [self updateUserInforView:scrollView];
        [self updateNav:offset];
    }
}

為了方便,我將這部分判斷做成了宏定義

#define DW_CheckSelfClass(calssName) \
calssName *trueSelf = self; \
if ([self isKindOfClass:[DWCollectionDelegate class]]) { \
DWCollectionDelegate *delegate = (DWCollectionDelegate *)self; \
id original = delegate.originalDelegate; \
if ([original isKindOfClass:[calssName class]]) { \
calssName *vc = (calssName *)original; \
trueSelf = vc;\
}else{ \
return; \
} \
}else if([self isKindOfClass:[calssName class]]){ \
trueSelf = self; \
} \
\

所以损离,新的代碼為

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGPoint offset = scrollView.contentOffset;
    DW_CheckSelfClass(UserCenterViewController);
    [trueSelf updateUserInforView:scrollView];
    [trueSelf updateNav:offset];
}

這個問題暫時還沒有找到解決的方案哥艇。如果有大神出手,我會更新僻澎。如果路過的大神有方法貌踏,還請路見不平一聲吼。多謝窟勃!

在此列出已經(jīng)在DWCollectionDelegate實現(xiàn)的代理方法祖乳,在以下方法中可以不去判斷self的類型。
  • UICollectionViewDelegateFlowLayout
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section 
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section 
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
  • UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath 
  • UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView //不需要實現(xiàn)

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section //不需要實現(xiàn)

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath//不需要實現(xiàn)

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath

封裝思路

  • 代理方法重定向到DWCollectionViewDelegate拳恋,并保存原始代理類對象
  • 使用字典保存所有信息凡资,包括注冊的cell和model的類名、block等
  • 獲取所有代理方法,并將必要的代理方法做imp指向
  • 在DWCollectionViewDelegate對應的代理方法中取得字典中保存的數(shù)據(jù)做block隙赁,或者調(diào)用原始類對象的代理

PS

暴露兩個NSObject的擴展類

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垦藏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子伞访,更是在濱河造成了極大的恐慌掂骏,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厚掷,死亡現(xiàn)場離奇詭異弟灼,居然都是意外死亡,警方通過查閱死者的電腦和手機冒黑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門田绑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抡爹,你說我怎么就攤上這事掩驱。” “怎么了冬竟?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵欧穴,是天一觀的道長。 經(jīng)常有香客問我泵殴,道長涮帘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任笑诅,我火速辦了婚禮调缨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘苟鸯。我一直安慰自己同蜻,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布早处。 她就那樣靜靜地躺著,像睡著了一般瘫析。 火紅的嫁衣襯著肌膚如雪砌梆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天贬循,我揣著相機與錄音咸包,去河邊找鬼。 笑死杖虾,一個胖子當著我的面吹牛烂瘫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼坟比,長吁一口氣:“原來是場噩夢啊……” “哼芦鳍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起葛账,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤柠衅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后籍琳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菲宴,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年趋急,在試婚紗的時候發(fā)現(xiàn)自己被綠了喝峦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡呜达,死狀恐怖愈犹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闻丑,我是刑警寧澤漩怎,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站嗦嗡,受9級特大地震影響勋锤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侥祭,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一叁执、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矮冬,春花似錦谈宛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至琼牧,卻和暖如春恢筝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巨坊。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工撬槽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人趾撵。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓侄柔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子暂题,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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

  • iOS網(wǎng)絡架構(gòu)討論梳理整理中移剪。。敢靡。 其實如果沒有APIManager這一層是沒法使用delegate的挂滓,畢竟多個單...
    yhtang閱讀 5,165評論 1 23
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件啸胧、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,024評論 4 62
  • 【銷售八大方法】 1赶站、最基本的銷售方法:賣文化、賣自己纺念、賣產(chǎn)品 2贝椿、最有效的銷售方法:事實與數(shù)據(jù) 3、最持續(xù)的銷售...
    連佩麗閱讀 363評論 0 0
  • 漸漸討厭一個人的感覺陷谱,就像是針管慢慢刺入皮膚烙博,由緊張到適應,刺痛到麻木烟逊,直到針被抽出渣窜,冒出殷紅的血,淡淡的血...
    ZSSXH閱讀 207評論 0 0