iOS 进阶+面试(三)

本篇文章是承接上篇文章 iOS 进阶+面试(二)

二十一、可变数组与不可变数组用什么修饰:原因?

地址https://www.jianshu.com/p/27305b08b0f2

二十二、nsstring 使用什么关键字修饰?

地址https://www.jianshu.com/p/9b77d61d76fe

二十三、线上项目崩溃,日志处理?

友盟, 集成需要在

-(void)viewWillAppear:(BOOL)animated
-(void)viewWillDisappear:(BOOL)animated
2368070-db2e7b98f2ef9589.png

详解 : 用友盟详细说明一下

  • 报表中心中下载错误
  • 友盟Crash分析工具与下载的错误报表放同一文件夹中, 打开 终端 , 先拖入友盟Crash分析工具** 再拖入 错误报表 , 按回车
  1. 进入友盟 个人中心 -> 错误分析 -> 错误列表 -> 点击列表中错误进入界面
2368070-da6c7ccaf8c7757c.png

2. 点击 右上角 进入 [报表中心] 下载该错误. 将 友盟Crash分析工具与下载的错误报表放同一文件夹中, 打开 终端 , 先拖入友盟Crash分析工具 再拖入 错误报表 , 按回车.

2368070-f9b083e8a22d57b7.png
  1. 终端 运行完成后 , 会显示错误的位置与行数

二十四、谈谈多线程的理解?

  • 使用线程可以把程序中占据时间长的任务放到后台去处理,如图片、视频的下载
  • 充分利用系统的多核 发挥多核处理器的优势,并发执行让系统运行的更快、更流畅,用户体验更好

缺点:

  • 更多的线程需要更多的内存空间

  • 当多个线程对同一个资源出现争夺的时候要注意线程安全的问题。

二十五、iPhone x max这个你们是怎样适配的?

iOS11之前导航栏默认高度为64pt(这里高度指statusBar + NavigationBar),iOS11之后如果设置了prefersLargeTitles = YES则为96pt,默认情况下还是64pt,但在iPhoneX上由于刘海的出现statusBar由以前的20pt变成了44pt,所以iPhoneX上高度变为88pt,如果项目里隐藏了导航栏加了自定义按钮之类的,这里需要注意适配一下。

之前是按照定义宏变量适配的,这个感觉每次新出手机都要重新适配新手机,iOS11 新出安全区域的概念,这是我们可以根据安全区域来适配,


2361189-9b6ed5e97f74d0c3.png

问题:

  • 导航栏图层及对titleView布局的影响

iOS11之前导航栏的title是添加在UINavigationItemView上面,而navigationBarButton则直接添加在UINavigationBar上面,如果设置了titleView,则titleView也是直接添加在UINavigationBar上面。iOS11之后,大概因为largeTitle的原因,视图层级发生了变化,如果没有给titleView赋值,则titleView会直接添加在_UINavigationBarContentView上面,如果赋值了titleView,则会把titleView添加在_UITAMICAdaptorView上,而navigationBarButton被加在了_UIButtonBarStackView上,然后他们都被加在了_UINavigationBarContentView上,如图:


20170926171451245.jpg

所以如果你的项目是自定义的navigationBar,那么在iOS11上运行就可能出现布局错乱的bug,解决办法是重写UINavigationBar的layoutSubviews方法,调整布局,上代码:

- (void)layoutSubviews {
  [super layoutSubviews];
  //注意导航栏及状态栏高度适配
  self.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), naviBarHeight);
  for (UIView *view in self.subviews) {
    if([NSStringFromClass([view class]) containsString:@"Background"]) {
      view.frame = self.bounds;
    }
    else if ([NSStringFromClass([view class]) containsString:@"ContentView"]) {
      CGRect frame = view.frame;
      frame.origin.y = statusBarHeight;
      frame.size.height = self.bounds.size.height - frame.origin.y;
      view.frame = frame;
    }
  }
}
  • UIScrollView、UITableView、UICollectionView

大家在iOS11设备上运行出现最多问题应该就是tableview莫名奇妙的偏移20pt或者64pt了。。原因是iOS11弃用了automaticallyAdjustsScrollViewInsets属性,取而代之的是UIScrollView新增了contentInsetAdjustmentBehavior属性,这一切的罪魁祸首都是新引入的safeArea,关于safeArea适配这篇文章iOS 11 安全区域适配总结讲的很详细,感兴趣的可以看下,我直接贴适配代码,因为低版本直接用contentInsetAdjustmentBehavior会报警告,所有定义了如下的宏(感谢@炒鸡范的指正,之前的宏犯了个低级错误...现改为)

#define adjustsScrollViewInsets(scrollView)\
do {\
_Pragma("clang diagnostic push")\
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\
if ([scrollView respondsToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\
  NSMethodSignature *signature = [UIScrollView instanceMethodSignatureForSelector:@selector(setContentInsetAdjustmentBehavior:)];\
  NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\
  NSInteger argument = 2;\
  invocation.target = scrollView;\
  invocation.selector = @selector(setContentInsetAdjustmentBehavior:);\
  [invocation setArgument:&argument atIndex:2];\
  [invocation retainArguments];\
  [invocation invoke];\
}\
_Pragma("clang diagnostic pop")\
} 

还有的发现某些界面tableView的sectionHeader、sectionFooter高度与设置不符的问题,在iOS11中如果不实现 -tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection: ,则-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不会被调用,导致它们都变成了默认高度,这是因为tableView在iOS11默认使用Self-Sizing,tableView的estimatedRowHeight、estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,解决办法简单粗暴,就是实现对应方法或把这三个属性设为0。
如果你使用了Masonry,那么你需要适配safeArea

if (@available(iOS 11.0, *)) {
  make.edges.equalTo()(self.view.safeAreaInsets)
} else {
  make.edges.equalTo()(self.view)
}
  • TabBarController

在viewWillAppear时 tabbar高度是49(默认高度?)
在viewDidAppear时 tabbar高度是83(真实准确高度)

可我在viewDidLoad时候就开始绘制界面了 如何适配?

具体的实现逻辑就是写一个继承UITabBarController的类然后修改类里面的方法

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    if (@available(iOS 11.0, *)){
        for (UIView *view in self.view.subviews) {
            if ([view isKindOfClass:[UITabBar class]]) {
            //x的位置不变 y的位置你自己调调到UI满意 宽不变 高也不能变      最终只是改变一下y的相对位置
              view.frame = CGRectMake(view.frame.origin.x, self.view.bounds.size.height-64, view.frame.size.width, 83);
             }

        }
    
     }

}

之前这么写有一个问题,就是会出现tabbar在push和pop的时候有上移下移的问题,后来查了一些资料解决了这个问题,在需要展示tabbar的控制器中添加下面的代码就可以了

 - (void)viewWillDisappear:(BOOL)animated{
    if (iPhoneX) {
        if (@available(iOS 11.0, *)){
            // 修改tabBra的frame
            CGRect frame = self.tabBarController.tabBar.frame;
            frame.origin.y = [UIScreen mainScreen].bounds.size.height -64;
            self.navigationController.tabBarController.tabBar.frame = frame;
        }
        
    }
    
}
- (void)viewWillAppear:(BOOL)animated{
    if (iPhoneX) {
        if (@available(iOS 11.0, *)){
            // 修改tabBra的frame
            CGRect frame = self.tabBarController.tabBar.frame;
            frame.origin.y = [UIScreen mainScreen].bounds.size.height -64;
            self.navigationController.tabBarController.tabBar.frame = frame;
        }
        
    }
    
}

二十六、git的常见命令操作

git pull 拉下项目代码

git status 查看状态

git checkout --readme.txt 把readme.txt文件在工作去的修改全部撤销

git rm 用于删除一个文件

git branch dev 创建dev分支

git checkout dev 跳转到dev分支 //注意当前的要先提交然后再跳转

git checkout -b dev 创建并切换到dev分支

git branch 查看当前分支

二十七、http中的三次握手和四次挥手?

1:客户端向服务器发出连接请求报文
2:TCP服务器收到请求报文后,如果同意连接,则发出确认报文
3:TCP客户进程收到确认后,还要向服务器给出确认

思考:为什么要三次握手呢,有人说两次握手就好了?
举例:已失效的连接请求报文段。

client发送了第一个连接的请求报文,但是由于网络不好,这个请求没有立即到达服务端,而是在某个网络节点中滞留了,直到某个时间才到达server,本来这已经是一个失效

的报文,但是server端接收到这个请求报文后,还是会想client发出确认的报文,表示同意连接。假如不采用三次握手,那么只要server发出确认,新的建立就连接了,但其实这个

请求是失效的请求,client是不会理睬server的确认信息,也不会向服务端发送确认的请求,但是server认为新的连接已经建立起来了,并一直等待client发来数据,这样,server的

很多资源就没白白浪费掉了,采用三次握手就是为了防止这种情况的发生,server会因为收不到确认的报文,就知道client并没有建立连接。这就是三次握手的作用。

  • TCP的四次挥手 ?
    1、TCP发送一个FIN(结束),用来关闭客户到服务端的连接。
    2、服务端收到这个FIN,他发回一个ACK(确认),确认收到序号为收到序号+1,和SYN一样,一个FIN将占用一个序号
    3、 服务端发送一个FIN(结束)到客户端,服务端关闭客户端的连接。
    4、客户端发送ACK(确认)报文确认,并将确认的序号+1,这样关闭完成

思考:那么为什么是4次挥手呢?

为了确保数据能够完成传输。

  关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也

即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

可能有人会有疑问,tcp我握手的时候为何ACK(确认)和SYN(建立连接)是一起发送。挥手的时候为什么是分开的时候发送呢 ????

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,

思考:客户端突然挂掉了怎么办?

正常连接时,客户端突然挂掉了,如果没有措施处理这种情况,那么就会出现客户端和服务器端出现长时期的空闲。解决办法是在服务器端设置保活计时器,每当服务器收到

客户端的消息,就将计时器复位。超时时间通常设置为2小时。若服务器超过2小时没收到客户的信息,他就发送探测报文段。若发送了10个探测报文段,每一个相隔75秒,

还没有响应就认为客户端出了故障,因而终止该连接。

  • 四、TCP和UDP的区别

我这里简单列举几个,因为我还没有研究UDP这个协议。

1、基于连接与无连接;UDP是无连接的,即发送数据之前不需要建立连接

2、TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付

   ,即不保证可靠交付Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。

5、TCP对系统资源要求较多,UDP对系统资源要求较少。

二十八、IOS 保证线程同步方式&性能对比

二十九、数据库

文章 https://www.jianshu.com/p/d8b980b41de4

三十、iOS中UITableViewCell的重用机制原理?

  • 重用实现分析

查看UITableView头文件,会找到NSMutableArray* visiableCells,和NSMutableDictnery* reusableTableCells两个结构。visiableCells内保存当前显示的cells,reusableTableCells保存可重 用的cells

TableView显示之初,reusableTableCells为空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。开始的cell都是通过 [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]来创建,而且cellForRowAtIndexPath只是调用最大显示cell数的 次数

比如:有100条数据,iPhone一屏最多显示10个cell。程序最开始显示TableView的情况是:

1. 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]创建10次cell,并给cell指定同样的重用标识(当然,可以为不同显示类型的 cell指定不同的标识)。并且10个cell全部都加入到visiableCells数组,reusableTableCells为空。

2. 向下拖动tableView,当cell1完全移出屏幕,并且cell11(它也是alloc出来的,原因同上)完全显示出来的时候。cell11加入到 visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。

3. 接着向下拖动tableView,因为reusableTableCells中已经有值,所以,当需要显示新的 cell,cellForRowAtIndexPath再次被调用的时候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。cell1加入到 visiableCells,cell1移出reusableTableCells;cell2移出visiableCells,cell2加入到 reusableTableCells。之后再需要显示的Cell就可以正常重用了。

所以整个过程并不难理解,但需要注意正是因为这样的原因:配置Cell的时候一定要注意,对取出的重用的cell做重新赋值,不要遗留老数据

  • 一些情况

使用过程中,我注意到,并不是只有拖动超出屏幕的时候才会更新reusableTableCells表,还有:

1. reloadData,这种情况比较特殊。一般是部分数据发生变化,需要重新刷新cell显示的内容时调用。在 cellForRowAtIndexPath调用中,所有cell都是重用的。我估计reloadData调用后,把visiableCells中所有 cell移入reusableTableCells,visiableCells清空。cellForRowAtIndexPath调用后,再把 reuse的cell从reusableTableCells取出来,放入到visiableCells。

2. reloadRowsAtIndex,刷新指定的IndexPath。如果调用时reusableTableCells为空,那么 cellForRowAtIndexPath调用后,是新创建cell,新的cell加入到visiableCells。老的cell移出 visiableCells,加入到reusableTableCells。于是,之后的刷新就有cell做reuse了。

三十一、遇到tableView卡顿嘛?会造成卡顿的原因大致有哪些?

1.最常用的就是cell的重用, 注册重用标识符

如果不重用cell时,每当一个cell显示到屏幕上时,就会重新创建一个新的cell

如果有很多数据的时候,就会堆积很多cell。

如果重用cell,为cell创建一个ID,每当需要显示cell 的时候,都会先去缓冲池中寻找可循环利用的cell,如果没有再重新创建cell

2.避免cell的重新布局

cell的布局填充等操作 比较耗时,一般创建时就布局好

如可以将cell单独放到一个自定义类,初始化时就布局好

3.提前计算并缓存cell的属性及内容

当我们创建cell的数据源方法时,编译器并不是先创建cell 再定cell的高度

而是先根据内容一次确定每一个cell的高度,高度确定后,再创建要显示的cell,滚动时,每当cell进入凭虚都会计算高度,提前估算高度告诉编译器,编译器知道高度后,紧接着就会创建cell,这时再调用高度的具体计算方法,这样可以方式浪费时间去计算显示以外的cell

4.减少cell中控件的数量

尽量使cell得布局大致相同,不同风格的cell可以使用不用的重用标识符,初始化时添加控件,

不适用的可以先隐藏

5.不要使用ClearColor,无背景色,透明度也不要设置为0

渲染耗时比较长

6.使用局部更新

如果只是更新某组的话,使用reloadSection进行局部更

7.加载网络数据,下载图片,使用异步加载,并缓存

8.少使用addView 给cell动态添加view

9.按需加载cell,cell滚动很快时,只加载范围内的cell

10.不要实现无用的代理方法,tableView只遵守两个协议

11.缓存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这两者同时存在才会出现“窜动”的bug。所以我的建议是:只要是固定行高就写预估行高来减少行高调用次数提升性能。如果是动态行高就不要写预估方法了,用一个行高的缓存字典来减少代码的调用次数即可

12.不要做多余的绘制工作。在实现drawRect:的时候,它的rect参数就是需要绘制的区域,这个区域之外的不需要进行绘制。例如上例中,就可以用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判断是否需要绘制image和text,然后再调用绘制方法。

13.预渲染图像。当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,然后再绘制到屏幕;

14.使用正确的数据结构来存储数据。

三十二、runloop 使用

文章

􏲩􏲪􏱦􏰿􏲫􏰑􏰚􏲬􏰫􏲭􏲩􏲪􏱦􏰿􏲫􏰑􏰚􏲬􏰫􏲭􏲮􏲩􏲪􏱦􏰿􏲫􏰑􏰚􏲬􏰫􏲭􏲮􏲩􏲪􏱦􏰿􏲫􏰑􏰚􏲬􏰫􏲭􏲮􏲩􏲪􏱦􏰿􏲫􏰑􏰚􏲬􏰫􏲭􏲮概念:

运行循环,保持程序的运行,处理应用中的各种事件,有事就做,没事休息,可以节省CPU的资源 ,提高程序性能

1、讲讲 RunLoop,项目中有用到吗?
2、RunLoop内部实现逻辑?
3、Runloop和线程的关系?

每条线程都有唯一的一个与之对应的RunLoop对象
RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value
主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建
RunLoop在第一次获取时创建,在线程结束时销毁

4、timer 与 Runloop 的关系?
5、程序中添加每3秒响应一次的NSTimer,当拖动tableview时timer可能无法响应要怎么解决?
6、Runloop 是怎么响应用户操作的, 具体流程是什么样的?
7、说说RunLoop的几种状态?
8、Runloop的mode作用是什么?

1、Runloop 的应用:
NSTimer 、 imageview 显示、performselector、常驻线程、自动释放池

2、Runloop 相关类

//
CFRunLoopRef
// 代表运行模式:每次启动,只能制定一个模式,如果需要切换,只能退出当前roop,这样做的目的是为了区分开不同的 timer/source/observer
CFRunLoopModeRef 
// 事件输入源  
// 1. Source1 : 基于Port的线程间通信   2. Source0 : 触摸事件,PerformSelectors
CFRunLoopSourceRef 
// 基于时间的触发器,但是会受到 mode 的影响,但是GCD定时器不会受到影响
CFRunLoopTimerRef 
// 观察者 监听roop 的状态
// 可以监听的时间点:
// 1、即将进入kcfRunLoopEntry
// 2、即将处理timer   kcfRunLoopBeforeTimers(􏲁􏳲􏲳􏱸timer)
// 3、即将处理source  kcfRunLoopBeforeSources(􏲁􏳲􏲳􏱸source)
// 4、即将进入休眠  kcfRunLoopBeforeWaiting(􏲁􏳲􏰩􏰪􏳔􏳳)
// 5、刚从休眠中唤醒 kcfRunLoopAfterWaiting(􏳴􏲩􏳔􏳳􏱬􏳵􏳶)
// 6、退出  kcfRunLoopExit(􏲁􏳲􏳍􏱍loop) 
CFRunLoopObserverRef

3、Runloop 的实现机制 以及在多线程中的使用

实现机制:保持程序的运行,处理应用中的各种事件,有事就做,没事休息,可以节省CPU的资源 ,提高程序性能

处理逻辑:
(1)、通知observer ,即将进入 runloop
(2)、通知observer ,即将处理 timer
(3)、通知observer ,即将处理 source0
(4)、如果有 source0,处理
(5)、通知observer ,即将休眠
(6)、通知observer ,即将唤醒
(7)、处理未处理的事件
(8)、线程退出

4、autorelease 对象什么时候被释放?
分两种情况:
1、手动干预释放:就是制定autoreleasepool ,超出当前作用预就释放
2、系统自动释放:当前runloop退出,就释放

5、mode 的作用是什么?
主要是用来制定优先级的

6、nstimer 的使用注意事项:
(1)、将 nstimer 实例添加到runloop 的时候,应该注意 类型mode
(2)、不用的时候 一定要调用 invalidate 方法 ,不调用就会引起内存泄漏 而且用 xcode 找不到

7、UITableViewCell 上有一个 UILable ,用于显示时间,滑动的过程中是否刷新时间呢?

如果在创建定时器的过程中使用的是 NSDefaultRunLoopMode 模式,在滑动过程中是不会调的,因为 该模式是运行在 空闲状态下的。默认模式的优先级比较低。

8、子线程中performSelector afterDelay

performSelector


今天用几个例子来记录一下performSelector的各种用法和注意事项

performSelector:withObject
此方法同步阻塞当前线程 它走完再走后面的方法

performSelectorOnMainThread:withObject:waitUntilDone
此方法可以在主线程或者子线程去调 但selector方法运行在主线程
waitUntilDone:YES 同步阻塞 自己走完再走后面方法
waitUntilDone:NO    异步非阻塞

performSelector:withObject:afterDelay
此方法是异步非阻塞!! 不能在没有runloop的子线程直接调 直接调的话不会生效
如果想要在子线程中生效可以:

给这个子线程加runloop
让这个方法在一个你创建的新的带有runloop的子线程中perform
不用performSelector:withObject:afterDelay改用dispatch_after


    1. afterDelay 方式是使用当前线程的定时器在一定时间后调用SEL,NO AfterDelay方式是直接调用SEL.
    2. 主线程的runloop默认开启,子线程的runloop默认不开启,所以timer在子线程中是不会执行的,需要手动开启runloop。

三十三、weak 与 assign 的区别

1、区别

1.修饰变量类型的区别

weak 只可以修饰对象。如果修饰基本数据类型,编译器会报错-“Property with ‘weak’ attribute must be of object type”。
assign 可修饰对象,和基本数据类型。当需要修饰对象类型时,MRC时代使用unsafe_unretained。当然,unsafe_unretained也可能产生野指针,所以它名字是"unsafe_”。

2.是否产生野指针的区别

weak 不会产生野指针问题。因为weak修饰的对象释放后(引用计数器值为0),指针会自动被置nil,之后再向该对象发消息也不会崩溃。 weak是安全的。
assign 如果修饰对象,会产生野指针问题;如果修饰基本数据类型则是安全的。修饰的对象释放后,指针不会自动被置空,此时向对象发消息会崩溃。

二、相似

都可以修饰对象类型,但是assign修饰对象会存在问题。

三、总结

assign 适用于基本数据类型如int,float,struct等值类型,不适用于引用类型。因为值类型会被放入栈中,遵循先进后出原则,由系统负责管理栈内存。而引用类型会被放入堆中,需要我们自己手动管理内存或通过ARC管理。
weak 适用于delegate和block等引用类型,不会导致野指针问题,也不会循环引用,非常安全。

三十四、常见的审核 反馈问题有哪些?

文章 https://www.jianshu.com/p/0de01db729c8

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

推荐阅读更多精彩内容