【阿崢教你實現(xiàn)UITableView循環(huán)利用】 |那些人追的干貨

前言

大家都知道UITableView,最經(jīng)典在于循環(huán)利用槽地,這里我自己模仿UITableView循環(huán)利用,寫了一套自己的TableView實現(xiàn)方案烧栋,希望大家看了我的文章,循環(huán)利用思想有顯著提升苇倡。
效果如圖:

tableView效果.gif

如果喜歡我的文章富纸,可以關(guān)注我,

研究UITableView底層實現(xiàn)

1.系統(tǒng)UITabelView的簡單使用旨椒,這里就不考慮分組了晓褪,默認(rèn)為1組。

// 返回第section組有多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"%s",__func__);
    return 10;
}

// 返回每一行cell的樣子
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%s",__func__);
    static NSString *ID = @"cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];

    }

    cell.textLabel.text = [NSString stringWithFormat:@"%ld",indexPath.row];

    return cell;
}

// 返回每行cell的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"%s--%@",__func__,indexPath);
    return 100;
}

2.驗證UITabelView的實現(xiàn)機制综慎。

如圖打印結(jié)果:

Snip20150808_3.png

分析:底層先獲取有多少cell(10個)涣仿,在獲取每個cell的高度,返回高度的方法一開始調(diào)用10次示惊。

目的:確定tableView的滾動范圍变过,一開始計算所有cell的frame,就能計算下tableView的滾動范圍。

分析:tableView:cellForRowAtIndexPath:方法什么時候調(diào)用涝涤。
打印驗證媚狰,如圖:

Snip20150808_5.png

一開始調(diào)用了7次,因為一開始屏幕最多顯示7個cell
目的:一開始只加載顯示出來的cell阔拳,等有新的cell出現(xiàn)的時候會繼續(xù)調(diào)用這個方法加載cell崭孤。

3.UITableView循環(huán)利用思想

當(dāng)新的cell出現(xiàn)的時候,首先從緩存池中獲取糊肠,如果沒有獲取到辨宠,就自己創(chuàng)建cell。
當(dāng)有cell移除屏幕的時候货裹,把cell放到緩存池中去嗤形。

二、自定義UIScrollView弧圆,模仿UITableView循環(huán)利用

1.提供數(shù)據(jù)源和代理方法赋兵,命名和UITableView一致

@class YZTableView;
@protocol YZTableViewDataSource<NSObject>

@required

// 返回有多少行cell
- (NSInteger)tableView:(YZTableView *)tableView numberOfRowsInSection:(NSInteger)section;



// 返回每行cell長什么樣子
- (UITableViewCell *)tableView:(YZTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

@end

@protocol YZTableViewDelegate<NSObject, UIScrollViewDelegate>

// 返回每行cell有多高
- (CGFloat)tableView:(YZTableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

@end


2.提供代理和數(shù)據(jù)源屬性

@interface YZTableView : UIScrollView

@property (nonatomic, weak) id<YZTableViewDataSource> dataSource;

@property (nonatomic, weak) id<YZTableViewDelegate> delegate;

@end

警告:

Snip20150816_1.png

解決搔预,在YZTableView.m的實現(xiàn)中聲明霹期。

Snip20150816_2.png

原因:有人會問為什么我要定義同名的delegate屬性,我主要想模仿系統(tǒng)的tableView拯田,系統(tǒng)tableView也有同名的屬性历造。

思路:這樣做,外界在使用設(shè)置我的tableView的delegate,就必須遵守的我的代理協(xié)議吭产,而不是UIScrollView的代理協(xié)議侣监。

3.提供刷新方法reloadData,因為tableView通過這個刷新tableView臣淤。

@interface YZTableView : UIScrollView

@property (nonatomic, weak) id<YZTableViewDataSource> dataSource;

@property (nonatomic, weak) id<YZTableViewDelegate> delegate;

// 刷新tableView
- (void)reloadData;

@end

4.實現(xiàn)reloadData方法橄霉,刷新表格

  • 回顧系統(tǒng)如何刷新tableView
    • 1.先獲取有多少cell,在獲取每個cell的高度。因此應(yīng)該是先計算出每個cell的frame.
    • 2.然后再判斷當(dāng)前有多少cell顯示在屏幕上荒典,就加載多少
// 刷新tableView
- (void)reloadData
{
    // 這里不考慮多組酪劫,假設(shè)tableView默認(rèn)只有一組。

    // 先獲取總共有多少cell
    NSInteger rows = [self.dataSource tableView:self numberOfRowsInSection:0];

    // 遍歷所有cell的高度寺董,計算每行cell的frame
    CGRect cellF;
    CGFloat cellX = 0;
    CGFloat cellY = 0;
    CGFloat cellW = self.bounds.size.width;
    CGFloat cellH = 0;

    CGFloat totalH = 0;

    for (int i = 0; i < rows; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        // 注意:這里獲取的delegate覆糟,是UIScrollView中聲明的屬性
        if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {
            cellH = [self.delegate tableView:self heightForRowAtIndexPath:indexPath];
        }else{
            cellH = 44;
        }
        cellY = i * cellH;

        cellF = CGRectMake(cellX, cellY, cellW, cellH);

        // 記錄每個cell的y值對應(yīng)的indexPath
        self.indexPathDict[@(cellY)] = indexPath;

        // 判斷有多少cell顯示在屏幕上,只加載顯示在屏幕上的cell
        if ([self isInScreen:cellF]) { // 當(dāng)前cell的frame在屏幕上
            // 通過數(shù)據(jù)源獲取cell
            UITableViewCell *cell = [self.dataSource tableView:self cellForRowAtIndexPath:indexPath];

            cell.frame = cellF;

            [self addSubview:cell];

        }

        // 添加分割線
        UIView *divideV = [[UIView alloc] initWithFrame:CGRectMake(0, cellY + cellH - 1, cellW, 1)];
        divideV.backgroundColor = [UIColor lightGrayColor];
        divideV.alpha = 0.3;
        [self addSubview:divideV];

        // 添加到cell可見數(shù)組中
            [self.visibleCells addObject:cell];

        // 計算tableView內(nèi)容總高度
        totalH += cellY + cellH;

    }

    // 設(shè)置tableView的滾動范圍
    self.contentSize = CGSizeMake(self.bounds.size.width, totalH);

}

5.如何判斷cell顯示在屏幕上

  • 當(dāng)tableView內(nèi)容往下走


    當(dāng)tableView內(nèi)容往下走.gif
  • 當(dāng)tableView內(nèi)容往上走

當(dāng)tableView內(nèi)容往上走.gif

// 根據(jù)cell尺寸判斷cell在不在屏幕上
- (BOOL)isInScreen:(CGRect)cellF
{
    // tableView能滾動,因此需要加上偏移量判斷

    // 當(dāng)tableView內(nèi)容往下走遮咖,offsetY會一直增加 ,cell的最大y值 < offsetY偏移量   ,cell移除屏幕
    // tableView內(nèi)容往上走 , offsetY會一直減少滩字,屏幕的最大Y值 <  cell的y值 ,Cell移除屏幕
    // 屏幕最大y值 = 屏幕的高度 + offsetY

    // 這里拿屏幕來比較御吞,其實是因為tableView的尺寸我默認(rèn)等于屏幕的高度麦箍,正常應(yīng)該是tableView的高度。
    // cell在屏幕上陶珠, cell的最大y值 > offsetY && cell的y值 < 屏幕的最大Y值(屏幕的高度 + offsetY)

    CGFloat offsetY = self.contentOffset.y;

    return CGRectGetMaxY(cellF) > offsetY && cellF.origin.y < self.bounds.size.height + offsetY;

}


6.在滾動的時候挟裂,如果有新的cell出現(xiàn)在屏幕上,先從緩存池中取揍诽,沒有取到诀蓉,在創(chuàng)建新的cell.

分析:

  • 需要及時監(jiān)聽tableView的滾動,判斷下有沒有新的cell出現(xiàn)暑脆。
  • 大家都會想到scrollViewDidScroll方法渠啤,這個方法只要一滾動scrollView就會調(diào)用,但是這個方法有個弊端添吗,就是tableView內(nèi)部需要作為自身的代理沥曹,才能監(jiān)聽,這樣不好碟联,有時候外界也需要監(jiān)聽滾動妓美,因此自身類最好不要成為自己的代理。(設(shè)計思想

解決:

  • 重寫layoutSubviews玄帕,判斷當(dāng)前哪些cell顯示在屏幕上部脚。
  • 因為只要一滾動,就會修改contentOffset,就會調(diào)用layoutSubviews裤纹,其實修改contentOffset,內(nèi)部其實是修改tableView的bounds,而layoutSubviews剛好是父控件尺寸一改就會調(diào)用.具體需要了解scrollView底層實現(xiàn)

思路:

  • 判斷下鹰椒,當(dāng)前tableView內(nèi)容往上移動锡移,還是往下移動,如何判斷漆际,取出顯示在屏幕上的第一次cell淆珊,當(dāng)前偏移量 > 第一個cell的y值,往下走奸汇。

  • 需要搞個數(shù)組記錄下施符,當(dāng)前有多少cell顯示在屏幕上,在一開始的時候記錄.

@interface YZTableView ()

@property (nonatomic, strong) NSMutableArray *visibleCells;

@end


@implementation YZTableView

@dynamic delegate;

- (NSMutableArray *)visibleCells
{
    if (_visibleCells == nil) {
        _visibleCells = [NSMutableArray array];
    }
    return _visibleCells;
}
@end

  • 往下移動
    • 如果已經(jīng)滾動到tableView內(nèi)容最底部擂找,就不需要判斷新的cell戳吝,直接返回.
    • 需要判斷之前顯示在屏幕cell有沒有移除屏幕
    • 只需要判斷下當(dāng)前可見cell數(shù)組中第一個cell有沒有離開屏幕
    • 只需要判斷下當(dāng)前可見cell數(shù)組中最后一個cell的下一個cell顯沒顯示在屏幕上即可。
  // 判斷有沒有滾動到最底部
        if (offsetY + self.bounds.size.height > self.contentSize.height) {
            return;
        }

        // 判斷下當(dāng)前可見cell數(shù)組中第一個cell有沒有離開屏幕
        if ([self isInScreen:firstCell.frame] == NO) { // 如果不在屏幕
            // 從可見cell數(shù)組移除
            [self.visibleCells removeObject:firstCell];

            // 刪除第0個從可見的indexPath
            [self.visibleIndexPaths removeObjectAtIndex:0];

            // 添加到緩存池中
            [self.reuserCells addObject:firstCell];

            // 移除父控件
            [firstCell removeFromSuperview];

        }

        // 判斷下當(dāng)前可見cell數(shù)組中最后一個cell的下一個cell顯沒顯示在屏幕上
        // 這里需要計算下一個cell的y值贯涎,需要獲取對應(yīng)的cell的高度
        // 而高度需要根據(jù)indexPath听哭,從數(shù)據(jù)源獲取
        // 可以數(shù)組記錄每個可見cell的indexPath的順序,然后獲取對應(yīng)可見的indexPath的角標(biāo),就能獲取下一個indexPath.

        // 獲取最后一個cell的indexPath
        NSIndexPath *indexPath = [self.visibleIndexPaths lastObject];

        // 獲取下一個cell的indexPath
        NSIndexPath *nextIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0];

        // 獲取cell的高度
        if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {
            cellH = [self.delegate tableView:self heightForRowAtIndexPath:nextIndexPath];
        }else{
            cellH = 44;
        }

        // 計算下一個cell的y值
        cellY = lastCellY + cellH;

        // 計算下下一個cell的frame
        CGRect nextCellFrame = CGRectMake(cellX, cellY, cellW, cellH);

        if ([self isInScreen:nextCellFrame]) { // 如果在屏幕上塘雳,就加載

            // 通過數(shù)據(jù)源獲取cell
            UITableViewCell *cell = [self.dataSource tableView:self cellForRowAtIndexPath:nextIndexPath];

            cell.frame = nextCellFrame;

            [self insertSubview:cell atIndex:0];

            // 添加到cell可見數(shù)組中
            [self.visibleCells addObject:cell];

            // 添加到可見的indexPaths數(shù)組
            [self.visibleIndexPaths addObject:nextIndexPath];



        }

  • 往上移動
    • 如果已經(jīng)滾動到tableView最頂部陆盘,就不需要判斷了有沒有心的cell,直接返回.
    • 需要判斷之前顯示在屏幕cell有沒有移除屏幕
    • 只需要判斷下當(dāng)前可見cell數(shù)組中最后一個cell有沒有離開屏幕
    • 只需要判斷下可見cell數(shù)組中第一個cell的上一個cell顯沒顯示在屏幕上即可
    • 注意點:如果可見cell數(shù)組中第一個cell的上一個cell顯示到屏幕上败明,一定要記得是插入到可見數(shù)組第0個的位置隘马。

        // 判斷有沒有滾動到最頂部
        if (offsetY < 0) {
            return;
        }



        // 判斷下當(dāng)前可見cell數(shù)組中最后一個cell有沒有離開屏幕
        if ([self isInScreen:lastCell.frame] == NO) { // 如果不在屏幕
            // 從可見cell數(shù)組移除
            [self.visibleCells removeObject:lastCell];

            // 刪除最后一個可見的indexPath
            [self.visibleIndexPaths removeLastObject];

            // 添加到緩存池中
            [self.reuserCells addObject:lastCell];

            // 移除父控件
            [lastCell removeFromSuperview];

        }


        // 判斷下可見cell數(shù)組中第一個cell的上一個cell顯沒顯示在屏幕上
        // 獲取第一個cell的indexPath
        NSIndexPath *indexPath = self.visibleIndexPaths[0];


        // 獲取下一個cell的indexPath
        NSIndexPath *preIndexPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];

        // 獲取cell的高度
        if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {
            cellH = [self.delegate tableView:self heightForRowAtIndexPath:preIndexPath];
        }else{
            cellH = 44;
        }

        // 計算上一個cell的y值
        cellY = firstCellY - cellH;


        // 計算上一個cell的frame
        CGRect preCellFrame = CGRectMake(cellX, cellY, cellW, cellH);

        if ([self isInScreen:preCellFrame]) { // 如果在屏幕上,就加載

            // 通過數(shù)據(jù)源獲取cell
            UITableViewCell *cell = [self.dataSource tableView:self cellForRowAtIndexPath:preIndexPath];

            cell.frame = preCellFrame;

            [self insertSubview:cell atIndex:0];

            // 添加到cell可見數(shù)組中,這里應(yīng)該用插入妻顶,因為這是最上面一個cell,應(yīng)該插入到數(shù)組第0個
            [self.visibleCells insertObject:cell atIndex:0];

            // 添加到可見的indexPaths數(shù)組,這里應(yīng)該用插入酸员,因為這是最上面一個cell,應(yīng)該插入到數(shù)組第0個
            [self.visibleIndexPaths insertObject:preIndexPath atIndex:0];

        }


    }


問題1:

  • 判斷下當(dāng)前可見cell數(shù)組中最后一個cell的下一個cell顯沒顯示在屏幕上

  • 這里需要計算下一個cell的frame,frame就需要計算下一個cell的y值,需要獲取對應(yīng)的cell的高度 cellY = lastCellY + cellH

  • 而高度需要根據(jù)indexPath盈包,從數(shù)據(jù)源獲取

解決:

  • 可以搞個字典記錄每個可見cell的indexPath,然后獲取對應(yīng)可見的indexPath沸呐,就能獲取下一個indexPath.
@interface YZTableView ()

// 屏幕可見數(shù)組
@property (nonatomic, strong) NSMutableArray *visibleCells;

// 緩存池
@property (nonatomic, strong) NSMutableSet *reuserCells;


// 記錄每個可見cell的indexPaths的順序
@property (nonatomic, strong) NSMutableDictionary *visibleIndexPaths;

@end

- (NSMutableDictionary *)visibleIndexPaths
{
    if (_visibleIndexPaths == nil) {
        _visibleIndexPaths = [NSMutableDictionary dictionary];
    }

    return _visibleIndexPaths;
}

注意:

  • 當(dāng)cell從緩存池中移除,一定要記得從可見數(shù)組cell中移除呢燥,還有可見cell的indexPath也要移除.
        // 判斷下當(dāng)前可見cell數(shù)組中第一個cell有沒有離開屏幕
        if ([self isInScreen:firstCell.frame] == NO) { // 如果不在屏幕
            // 從可見cell數(shù)組移除
            [self.visibleCells removeObject:firstCell];

            // 刪除第0個從可見的indexPath
            [self.visibleIndexPaths removeObjectAtIndex:0];

            // 添加到緩存池中
            [self.reuserCells addObject:firstCell];

        }

 // 判斷下當(dāng)前可見cell數(shù)組中最后一個cell有沒有離開屏幕
        if ([self isInScreen:lastCell.frame] == NO) { // 如果不在屏幕
            // 從可見cell數(shù)組移除
            [self.visibleCells removeObject:lastCell];

            // 刪除最后一個可見的indexPath
            [self.visibleIndexPaths removeLastObject];

            // 添加到緩存池中
            [self.reuserCells addObject:lastCell];

        }

7.緩存池搭建崭添,緩存池其實就是一個NSSet集合

  • 搞一個NSSet集合充當(dāng)緩存池.
  • cell離開屏幕叛氨,放進緩存池
  • 提供從緩存池獲取方法呼渣,從緩存池中獲取cell,記住要從NSSet集合移除cell.

@interface YZTableView ()

// 屏幕可見數(shù)組
@property (nonatomic, strong) NSMutableArray *visibleCells;

// 緩存池
@property (nonatomic, strong) NSMutableSet *reuserCells;

// 記錄每個cell的y值都對應(yīng)一個indexPath
@property (nonatomic, strong) NSMutableDictionary *indexPathDict;

@end
@implementation YZTableView
- (NSMutableSet *)reuserCells
{
    if (_reuserCells == nil) {

        _reuserCells = [NSMutableSet set];

    }
    return _reuserCells;
}


// 從緩存池中獲取cell
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
{
    UITableViewCell *cell = [self.reuserCells anyObject];

    // 能取出cell,并且cell的標(biāo)示符正確
    if (cell && [cell.reuseIdentifier isEqualToString:identifier]) {
        // 從緩存池中獲取
        [self.reuserCells removeObject:cell];

        return cell;
    }

    return nil;
}

@end

8.tableView細(xì)節(jié)處理

原因:
刷新方法經(jīng)常要調(diào)用

解決:
每次刷新的時候,先把之前記錄的全部清空

// 刷新tableView
- (void)reloadData
{

    // 刷新方法經(jīng)常要調(diào)用
    // 每次刷新的時候寞埠,先把之前記錄的全部清空
    // 清空indexPath字典
    [self.indexPathDict removeAllObjects];
    // 清空屏幕可見數(shù)組
    [self.visibleCells removeAllObjects];
    ...
}

聯(lián)系方式

如果你喜歡這篇文章屁置,可以繼續(xù)關(guān)注我,微博:吖了個崢,歡迎交流仁连。
點擊這下載源代碼蓝角。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阱穗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子使鹅,更是在濱河造成了極大的恐慌揪阶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件患朱,死亡現(xiàn)場離奇詭異鲁僚,居然都是意外死亡,警方通過查閱死者的電腦和手機裁厅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門冰沙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人执虹,你說我怎么就攤上這事拓挥。” “怎么了声畏?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵撞叽,是天一觀的道長。 經(jīng)常有香客問我插龄,道長愿棋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任均牢,我火速辦了婚禮糠雨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘徘跪。我一直安慰自己甘邀,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布垮庐。 她就那樣靜靜地躺著松邪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哨查。 梳的紋絲不亂的頭發(fā)上逗抑,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音寒亥,去河邊找鬼邮府。 笑死,一個胖子當(dāng)著我的面吹牛溉奕,可吹牛的內(nèi)容都是我干的褂傀。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼加勤,長吁一口氣:“原來是場噩夢啊……” “哼仙辟!你這毒婦竟也來了同波?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤欺嗤,失蹤者是張志新(化名)和其女友劉穎参萄,沒想到半個月后卫枝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煎饼,經(jīng)...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年校赤,在試婚紗的時候發(fā)現(xiàn)自己被綠了吆玖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡马篮,死狀恐怖沾乘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浑测,我是刑警寧澤翅阵,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站迁央,受9級特大地震影響掷匠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岖圈,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一讹语、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜂科,春花似錦顽决、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贡定,卻和暖如春赋访,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厕氨。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工进每, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命斧。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓田晚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親国葬。 傳聞我的和親對象是個殘疾皇子贤徒,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,781評論 2 361

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫芹壕、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,123評論 4 61
  • 概述在iOS開發(fā)中UITableView可以說是使用最廣泛的控件接奈,我們平時使用的軟件中到處都可以看到它的影子踢涌,類似...
    liudhkk閱讀 9,067評論 3 38
  • 在簡書里 我是誰 天南地北 天涯海角的 我和 你 相聚在簡書里 我不會告訴你 我是位全職媽媽 每天與孩子相伴 我不...
    明希美美閱讀 276評論 6 5
  • 露重深秋夜 披衣月下行 空吟無友對 抱憾意難平
    江南丹橘_a43d閱讀 396評論 5 14