tableView总结

本文旨在帮助各位大佬复习巩固基础知识。

一、tableView类型与系统自带cell类型
二、两种注册系统cell的方法
三、常用代理方法总结
四、实战练习
五、巩固提高-两个tableView的联动
六、感谢参考文章 与本文demo链接

一、tableView类型与系统自带cell类型

1、tableView样式可分为普通样式与分区样式两种:

UITableViewStylePlain、UITableViewStyleGrouped

两者的区别在于一个grouped样式可以有分区头,而plain样式则没有

2、cell样式可分为以下四种:

UITableViewCellStyleValue1、UITableViewCellStyleValue2、UITableViewCellStyleDefault、UITableViewCellStyleSubtitle

四种cell样式的区别在于imageView、textLabel、detailTextLabel、accessoryType 的位置、显示不同。

如图:


552b2419-655b-4639-b454-e4f11bd0bb82.gif

二、两种注册系统cell的方法

cell注册目的都在于cell的复用来节省开支。

1、常用的,在代理行为返回cell时进行注册(据了解:系统推荐用这个方法,这个方法在某些情况下更加能避免循环复用)


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // kPlaceHolderCellId是我定义的一个宏字符串

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPlaceHolderCellId];

    if (!cell) {

        cell = [[UITableViewCell alloc]initWithStyle:(UITableViewCellStyleValue1) reuseIdentifier:kPlaceHolderCellId];

    }

    return cell;

}

2、在tableView申请之后进行注册(这样在cellForRowAtIndexPath里就不需要对cell 是否为空进行判断)


 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kPlaceHolderCellId];

// 下面是代理方法,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPlaceHolderCellId];

    return cell;

} 

本文不对xib注册进行解释,详情可查看其他朋友文章。

三、常用代理方法总结

1、数据源:


// 返回第section组中有多少行 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section; 

// 返回多少组,没实现该方法,默认为1 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

2、UITableViewDelegate代理方法



// 即将显示tableviewcell时调用
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;

// 即将显示header时调用,在cell之后调用
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 即将显示footer时调用,在header之后调用
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 在删除cell之后调用,停止显示cell的时候调用,界面不显示cell时。
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath NS_AVAILABLE_IOS(6_0);

// 停止显示header的时候调用
- (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

// 停止显示footer的时候调用
- (void)tableView:(UITableView *)tableView didEndDisplayingFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0)

3、操作cell时调用的方法

// cell选中时调用
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
// cell取消选中时调用
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);

4、设置分组view的方法


// 返回某个section对应的header标题

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;

// 返回某个section对应的footer标题

- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section; 

// 设置第section分组的header 

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; 

// 设置第section分组的footer 

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;

5、高度的代理方法


// 在设置每行cell的高度,header的高度,footer的高度 

// 设置某行cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 

// 设置header高度

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section; 

// 设置footer高度 

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

6、编辑模式相关的代理方法

// 返回每一行cell的编辑模式, 可以再次设置add或者删除操作。
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
// cell左滑删除时,删除按钮的标题
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0);
// 自定义编辑左滑后出现的界面。  不止只有一个delete按钮, 可以自行定义,返回一个数组。数组中放着UITableviewRowAction
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
// 未实现 默认为yes,进入编辑时,cell是否缩进。  在开启编辑状态时调用。
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;

// 右滑准备进行编辑的时候 调用。 将setediting = yes时不调用
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
// 完成编辑的时候调用
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;

7、索引


//返回要显示的section索引标题

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView; 

// return list of section titles to display in section index view (e.g. "ABCD...Z#") 

// 点击右侧索引表项时调用

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index; 

// 返回指定点所在位置的indexPath 

- (NSIndexPath *)indexPathForRowAtPoint:(CGPoint)point; 

// 返回指定cell所在的indexPath

- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell;

// 返回指定范围rect中的所有cell的indexPath

- (NSArray *)indexPathsForRowsInRect:(CGRect)rect;

  // returns nil if rect not valid

// 返回索引indexPath所指向的cell。

- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;

8、tableview的滚动方法


// 根据传入的indexPath,滚动到相对应的位置,第二个参数是控制对应的cell再滚动后处于tableview的顶部/底部/中部等 

- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

// 滚动到被选中项。 滚动后处于tableview的顶部/底部/中部等

- (void)scrollToNearestSelectedRowAtScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

9、插入,删除,刷新,移动section组


// 插入,删除,刷新,移动section组 

// 插入section

- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation; 

// 删除section 

- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation; 

// 刷新section 

- (void)reloadSections:(NSIndexSet *)sections withRowAnimation: (UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0); 

// 移动section 

- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);

四、实战练习

1、自定义cell

效果图:

自定义cell.gif

1)、通过自定义cell可以实现各式各样的我们想要的样式,当cell定义后,如果我们暴露在外面的是label,则可以通过改变label的text属性来进行赋值,如果暴露到外面的是string,想通过string赋值来改变label的话,我使用的是rac进行监听string的变化。

2)、cell的定义可以通过高内聚来实现数据与controller的分离。


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    UITableViewCell *cell;

    if (indexPath.row%2 == 0) {

        // 通过cell的事件方法处理,将cell的定义在cell定义中进行自己的实现,这样就可以达到高内聚低耦合。 下面的model是定义的一种数据类型,这样congtroller也不需要管具体数据是什么了

        OneTableViewCell *oneCell = [OneTableViewCell createCellWithTableView:tableView];

        oneCell.myModel = _model;

        cell = oneCell;

    }else{

        // 通过传字符串处理,这个cell暴露在外面的string。我在cell实现中进行了rac监听

        TwoTableViewCell *oneCell = [tableView dequeueReusableCellWithIdentifier:kPlaceHolderCellId2];

        if (oneCell == nil) {

            oneCell = [[TwoTableViewCell alloc]initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:kPlaceHolderCellId2];

        }

        oneCell.nameStr = _nameArr[indexPath.row];

        oneCell.messageStr = _messageArr[indexPath.row];

        cell = oneCell;

    }

    return cell;

}

第一个cell


// 类方法用来作为cell对外的调用接口

+(instancetype)createCellWithTableView:(UITableView *)tableView{

    OneTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPlaceHolderCellId];

    if (cell == nil) {

        cell = [[OneTableViewCell alloc]initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:kPlaceHolderCellId];

    }

    return cell;

}

// 实现cell布局

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self) {

        id headerView = ImageView.img(@"header2.jpg").borderRadius(40);

        _nameLabel = Label.fitSize.str(_myModel.name);

        _messageLabel = Label.fitSize.str(_myModel.message);

        id messageView = View;

        id verS1 = VerStack(@5,

                 _nameLabel,

                 _messageLabel,).gap(5).embedIn(messageView);

        id verS2 = VerStack(@5,

                            headerView,

                            @5);

        HorStack(@5,verS2,verS1,NERSpring).gap(15).embedIn(self);

    }

    return self;

}

// model赋值

-(void)setMyModel:(YSCellModel *)myModel{

    _myModel = myModel;

    self.nameLabel.text = _myModel.name;

    self.messageLabel.text = _myModel.message;

    NSLog(@"执行了,%@",_myModel.name);

}

第二个cell


-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self) {

        id headerView = ImageView.img(@"header4.jpg").borderRadius(40);

        UILabel *nameLabel = Label.fitSize.str(_nameStr);

        UILabel *speakLabel = Label.fitSize.str(_messageStr);

        id messageView = View;

        id verS1 = VerStack(@5,

                            nameLabel,

                            speakLabel,).gap(5).embedIn(messageView);

        id verS2 = VerStack(@5,

                            headerView,

                            @5);

        HorStack(@5,verS2,verS1,NERSpring).gap(15).embedIn(self);

        // 通过rac监听string的改变来改变label的text

        [RACObserve(self, self.nameStr) subscribeNext:^(id  _Nullable x) {

            nameLabel.text = x;

        }];

        [RACObserve(self, messageStr) subscribeNext:^(id  _Nullable x) {

            speakLabel.text = x;

        }];

    }

    return self;

}

2、cell的侧滑按钮-cell的移动与编辑状态

效果图:

侧滑多按钮.gif

1)、cell的侧滑按钮可通过editActionsForRowAtIndexPath行为返回的数组来进行定义。

2)、cell的移动需要在编辑状态下实现canMoveRowAtIndexPath 和 moveRowAtIndexPath两个方法。

cell的侧滑实现


// 自定义编辑左滑后出现的界面。  不止只有一个delete按钮, 可以自行定义,返回一个数组。数组中放着UITableviewRowAction

-(NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{

    UITableViewRowAction *action0 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"关注" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {

        NSLog(@"点击了关注");

        // 收回左滑出现的按钮(退出编辑模式)

        tableView.editing = NO;

    }];

    UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {

        [self.myArray removeObjectAtIndex:indexPath.row];

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

    }];

    return @[action1, action0];

}

cell的编辑状态下的移动


// 在编辑状态下可以移动

-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{

    return YES;

}

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{

    // demo中并没有在这里操作,如果你不想退出程序后变回原样的话,就在这里对你的数据数组进行换位置

}

cell编辑的样式


// 返回cell支持的编辑样式   可以自己尝试查看每种样式的样子

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

    //表示支持默认操作

    //return UITableViewCellEditingStyleNone;

    //表示支持删除操作

//    return UITableViewCellEditingStyleDelete;

    //表示支持新增操作

//    return UITableViewCellEditingStyleInsert;

    return UITableViewCellEditingStyleDelete ;

}

3、mjrefresh的刷新

关于这个第三方库的使用,网上有蛮多教程的。这里只介绍一个切换图片的类似动图的刷新状态。

效果图(gif有点卡):

mjrefsh刷新.gif

代码


    MJRefreshGifHeader *header = [MJRefreshGifHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];

    NSArray *test = [NSArray arrayWithObjects:Img(@"header4.jpg"),Img(@"header2.jpg"), nil];

// 注意,只有隐藏了下面两个状态栏才能让图片在居中显示。如果你还希望自定义文字可查看demo,也可自己上网八一八更详细的资料 

    // 隐藏时间

    header.lastUpdatedTimeLabel.hidden = YES;

    // 隐藏状态栏

    header.stateLabel.hidden = YES;

4、多分区的删除cell - 索引

效果图:

1)、之所以单独拿出来讲是因为我这种菜鸡之前也不会,删除时候总是崩溃,所以总结了两种方法来删除多分区的cell。(demo中没有对一个分区中只有一个cell的情况进行适配)

2)、索引需要实现sectionIndexTitlesForTableView 和 sectionForSectionIndexTitle两个方法就可以了

删除cell


// Override to support editing the table view.

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

        // 首先获取对应分区的数组 然后删除数组中你删除的cell

        NSString *str = self.allKeys[indexPath.section];

        self.dataArray = [self.dictionary objectForKey:str];

        [self.dataArray removeObjectAtIndex:indexPath.row];

        if (self.dataArray.count == 0) {

            [self.dictionary removeObjectForKey:str];

            self.allKeys = [self.dictionary allKeys];

        }

        // 这样重新加载不能带动画的删除  这就是方法1

//        [self.tableView reloadData];

        // 这样可以带动画的删除cell   这样就是方法2

        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:(UITableViewRowAnimationFade)];

}

索引


//返回索引数组

-(NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView{

    return [self.allKeys sortedArrayUsingSelector:@selector(compare:)];

}

//响应点击索引时的委托方法

-(NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index{

    NSInteger count = 0;

    for (NSString *character in self.allKeys) {

        if ([[character uppercaseString] hasPrefix:title]) {

            return count;

        }

        count++;

    }

    return  0;

}

五、巩固提高-两个tableView的联动

tableview的联动有两种方式,有人说使用willDisplayHeaderView 和 didEndDisplayingHeaderView 方法会出现联动不准确的bug,也许我神经比价大条并没有感觉会有不准确的情况,不过第二种方法代码量确实较少。仁者见仁。以下为两种方法的实现方式

方法一


// 此处省略leftTable 和 rightTable的声明  和  数据的声明过程,详细代码稍后会发demo出来

#pragma mark 方法一

// 点击左侧可滚动右侧

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    if (tableView == _leftTabele) {

        NSInteger select = indexPath.row;

        [_rightTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:select] atScrollPosition:UITableViewScrollPositionTop animated:YES];

    }

}

// 标记右侧tableVIew是向下滚动还是向上滚动

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

    if (scrollView == self.leftTabele) return;

    static CGFloat lastOffsetY = 0;

    UITableView *tableview = (UITableView *)scrollView;

    if (tableview == _rightTable) {

        _isScrollDown = lastOffsetY < scrollView.contentOffset.y; // 手指向上拖动就为真,向下拖动就为假(界面向上滚动、界面向下滚动)

        lastOffsetY = scrollView.contentOffset.y; // 记录当前y值,向下变大,向上变小

//        NSLog(@"%@",_isScrollDown ? @"1":@"2");

    }

}

// 即将展示头部标题  手指向下拖动的时候才显示这个

-(void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section{

    // 当前tableView 是右侧的, 滑动方向向下,是用户拖拽产生的滚动

    if ((tableView ==  _rightTable) && !_isScrollDown && _rightTable.dragging) {

        NSLog(@"分区将要显示:%ld",section);

        [self selectRowAtIndexPath:section];

    }

}

// 分区标题展示结束 手指向上滑动的时候显示这个

-(void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section{

    // 当钱tableView 是右侧的,滚动方向是向上,是用户拖拽产生的滚动

    NSLog(@"t2:%d",_rightTable.dragging);

    if ((tableView == _rightTable) && _isScrollDown && _rightTable.dragging) {

        NSLog(@"分区将要隐藏:%ld",section);

        [self selectRowAtIndexPath:section];

    }

}

// 当拖动右边 tableView的时候,处理左边tableView

-(void)selectRowAtIndexPath:(NSInteger)index{

    [_leftTabele selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] animated:YES scrollPosition:(UITableViewScrollPositionTop)];

}

方法二

#pragma mark 方法二
// 此处省略leftTable 和 rightTable的声明  和  数据的声明过程,详细代码稍后会发demo出来

// 点击左侧可滚动右侧

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    if (tableView == _leftTabele) {

        NSInteger select = indexPath.row;

        [_rightTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:select] atScrollPosition:UITableViewScrollPositionTop animated:YES];

    }

}

// 标记右侧tableVIew是向下滚动还是向上滚动

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

    if (scrollView == self.leftTabele) return;

    NSLog(@"这里是视图上所有cell:%@",[self.rightTable indexPathsForVisibleRows]);

    NSLog(@"这里是最考上的一个cell:%@",[[self.rightTable indexPathsForVisibleRows] firstObject]);

    // 取出显示在 视图 且最靠上 的 cell 的 indexPath

    NSIndexPath *topHeaderViewIndexpath = [[self.rightTable indexPathsForVisibleRows] firstObject];

    // 左侧 talbelView 移动到的位置 indexPath

    NSIndexPath *moveToIndexpath = [NSIndexPath indexPathForRow:topHeaderViewIndexpath.section inSection:0];

    // 移动 左侧 tableView 到 指定 indexPath 居中显示

    [self.leftTabele selectRowAtIndexPath:moveToIndexpath animated:YES scrollPosition:UITableViewScrollPositionMiddle];

}

方法二解析图(图片来源于网络)

tableView联动解析.png

我遇到的bug

如图:

bug版联动.gif

bug描述:图片要展示的bug是,当滑动右侧tableView 的时候会直接从A分区跳到N分区,无论上拉还是下拉。后来解决这个bug,是因为我用的MAC外接了一个显示器,当使用快捷键ctrol+option进行快速屏幕拖动时出发了模拟器的option选项,从而导致了这个bug。解决办法就是在模拟器上再点击的时候再按住option就可以了。

鸣谢文章链接

iOS tableView详解

iOS两个 TableView 联动. 思路简单明了,无bug!

本文demo链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,299评论 8 265
  • 一、简介 <<UITableView(或简单地说,表视图)的一个实例是用于显示和编辑分层列出的信息的一种手段 <<...
    无邪8阅读 10,578评论 3 3
  • 有位来访者说,自己也不知道是为什么,丈夫家暴有5年多了,她却一直忍受。 她和丈夫结婚6年,婚姻生活开始不到半年,有...
    吴在天阅读 595评论 4 5
  • 一直都有听说promise,但是之前都没有用过,经过查阅了相关的资料后,想自己总结一下promise。 1.pro...
    小梁姐姐阅读 549评论 0 1