iOS知识树

原文出处:hherima

iOS知识树,知识点(包括对象、Block、消息转发、GCD、运行时、runloop、动画、Push、KVO、tableview,UIViewController、提交AppStore) - IOS - 伯乐在线

本文旨在总结iOS知识网络,知识点,该知识网络罗列出常见UIKit、Foundation的对象特点和一些使用经验,可以看成是一本书;文本编辑采用树的形式,对知识点进行罗列,并标注一些使用经验(★)希望对初学者有用或给一些解决疑难杂症者提供思路;某些知识点会深入探讨;通过总结希望站在一个较高平台的角度全观Objective-C。

知识树中有些是原创文章,有些则是转载网络上iOS大神的文章。由于篇幅的限制笔者会简洁地介绍各个知识点,读者可通过链接了解详情。当然一个人的知识面是相当有限的,在给各位读者提供知识参考的同时,欢迎大家对本文提意见。

/->UIViewController

|ViewController在iOS只是一个非常重要的概念,其在一个App中所扮演的角色:

|(1) View Management:管理View     (2) Data Marshalling:管理数据

|(3) User Interactions:响应用户交互 (4) Resource Management:管理资源

|(5) Adaptivity:适配不同的屏幕尺寸空间的变化

|生命周期【一片枫叶点击另外一篇点击

|+ (void)initialize +(void)load 的调用时机,区别【点击

|ViewDidLoad调用时机:当view被首次使用的时候,某些情况可提升性能

|横竖屏的坑【点击】。APP整体是竖屏,单个controller可以是横屏的

|两种交互方式:push和present

|左右滑动 - (void)pushViewController:(UIViewController *) animated:(BOOL)

|模态,从下往上弹出 - (void)presentViewController:(UIViewController *) animated: (BOOL) completion:

|还有一种:直接把Controller的view添加到另一个Controller上。

|->UIView

|frame 和bound 的区别【点击】

|frame 是相对父试图坐标的值; bound是本身坐标系统的值

|layoutSubviews【点击】需要将[super layoutSubviews];放到最后,不然iOS7有可能会有这个崩溃

|“Auto Layout still required after executing -layoutSubviews” iOS7上崩溃sdk缺陷【点击】

|每一个视图有唯一的父视图【点击】。addsubview操作把它从上一个父试图中移除

|善于使用hidden 使用animateWithDuration简单地控制页面切换效果

|使用animateWithDuration简单地控制页面切换效果【点击

|简单动画 animateWithDuration【点击

|->CALayer

|CALayer是个简单的类,它是用来在屏幕上显示内容展示的矩形区域.【容芳志出品点击

|直接从NSObject继承,少了UIResponder类,固CALayer悲催的不能响应任何用户事件【点击

|->UIWindow

|每一个IOS程序都有一个UIWindow

|UIWindow有三个层级,分别是Normal,StatusBar,Alert【点击】

|keyWindow是指定的用来接收键盘以及非触摸类的消息,

|而且程序中每一个时刻只能有一个window是keyWindow。

|->UIImage

|加载图片几种方式【点击】

|[UIImage imageNamed:@“xxx”] 系统缓存到cache中

|[UIImage imageWithContentsOfFile:path] 不缓存

|[UIImage imageWithData:data]  不缓存

|★拉伸图片,四角保持不变resizableImageWithCapInsets:

|加载gif图片【点击】

|->UILabel【点击】

|没有上下居中对齐,可以使用TTTAttributedLabel

|重写drawTextInRect:方法,可以自定义绘制区域,比如可设置Inset

|[super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.textInsets)];

/

/->UIKit

|

||->UIButton

||设置颜色,文字一定要指定button状态

||善于使用contentEdgeInsets,可以设置文本边距【点击】

||设置圆角可layer.cornerRadius

||->UITextfield

||隐藏键盘,[textfield resignFirstResponder]

||★任意页面隐藏键盘【点击】

||->UIScrollerView

||上拉下拉原理【点击

||->UITableView

||复用,注意重写 - (void)prepareForReuse

||dequeueReusableCellWithIdentifier 从重用池中获取,可能是nil

||dequeueReusableCellWithReuseIdentifier 同上,但是不会是nil

||插入,删除,移动section或item的顺序,需遵循下面两个步骤【点击

||1. 更新dataSource的数据

||2. 调用相应的collection view方法删除或者插入section或item

||★非常严格的条件:,在更新collection view之前,先更新datasource,

||因为collection view总是假设你已经准备好打他source了 否则collection view收到错误的item,并造成crash

||右侧音序条【点击】

||UITableView上拉、下拉原理【点击】

||AsyncDisplayKit 流畅的解决方法【点击

||tableView正在滚动的时候,如果reloadData,偶尔发生App crash的情况【点击

||UITableview Deceleration 加速滑动(惯性滑动)、弹性回归原理【点击

||->UIDevice

||设备名 [UIDevice currentDevice].name,

||系统版本号 [[UIDevice currentDevice].systemVersion doubleValue];【点击】

||屏幕旋转方向 [[UIDevice currentDevice] orientation]

||区分iPad还是iPhone [UIDevice currentDevice].userInterfaceIdiom);

||->UIScreen

||如何正确的绘制1像素的线【点击】

||保证边距不变,内容等比例拉伸【点击】

||->UIEdgeInsets

||实际显示边距,跟设置边距的距离【点击

|->自动布局

|Masonry

|storyboard

|

|/->NSObject既是对象也是协议,可以将对象自动置nil 比如 int = 0 bool = NO

||几乎所有类的基类或者协议【点击

||isKindOfClass:和isMemberOfClass:,通过这两种方法可以确定一个类的从属关系

||后者测试一个接收器是否是一个指定类的实例;而后者可以测试类的从属关系。

||respondsToSelector: 方法测试一个接收器是否通过selector实现(implements)了一个标志符话的方法

||description方法,允许一个对象返回一个字符串来描述它的内容;这个常用于调试debug

||encodeWithCoder: 和 initWithCoder:方法,NSCoding协议中仅有的组成成员

||第一个允许对象编译它的实例变量,第二个允许一个对象初始化它自身的解码实例变量。

||conformsToProtocol:方法,测试接收器(对象或者类)符合一个给定的协议(protocol)

||类对象中的 isa 指向类结构被称作 metaclass【点击】跟[object class]有点区别,比如KVO的时候

||__weak如何实现对象值自动设置为nil的【点击

||->NSString & NSMutableString

||NSString作为属性时候,用copy还是strong修饰?

||strong是单纯的增加对象的引用计数,而copy操作是执行了一次深拷贝【点击】

||->NSArray & NSMutableArray

||NSArray 各种遍历方式,倒序遍历【点击】

||NSArray简便初始化方法@[@"1",@"2"];

||浅拷贝。数组本身使用地址,但是数组item仍是旧对象【Apple 官方解释点击

||无论copy、arrayWithArray、copyWithZone 数组内对象并没有变。

||只是copy出来的array是新地址,arrayWithArray出来的数组也是新地址。

||深拷贝。数组本身使用地址,但是数组item是新地址

||[[NSArray alloc] initWithArray:someArray copyItems: YES];

||深拷贝时候,数组中的item必须实现NSCopying协议并实现copyWithZone:

||防止NSArray was mutated while being enumerated

||array包含array的情况深拷贝。NSArray* trueDeepCopyArray = [NSKeyedUnarchiver

||unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

||containsObject 注意:在对比数组中元素的时候,调用元素的isEqual的返回值。

||->NSDictionary & NSMutableDictionary

||取值时候,最好判断object的类型。    if ([object isKindOfClass:[NSString class]]){ //todo};

||->NSNumber 和 NSInteger NSRange

||前者专门用来装基础类型的对象,把整型、单精度、双精度、字符型等基础类型存储为对象

||->NSNullFMDB数据库,使用的时候崩溃

||JsonKit转换以后会生出相应的[NSNull null]对象【点击

||->NSData字节缓冲区

||+ (nullable instancetype)dataWithContentsOfURL:(NSURL *)url

||dataWithContentsOfURL 虽然是同步的,但可以结合gcd 异步加载网络图片【点击

||->NSUserDefaults【点击

||可用于APP setting默认值不好用,SDK bug

||设置WebVIew的UA【点击

||->NSDate & NSDateFormatter &NSCalendar

||可判断过去几个小时,还是几天 - (NSDateComponents *) components:fromDate:toDate:options:

||可获取时间戳

||有时候有8小时的时差,解决办法【点击

||在开发iOS程序时对日期处理的总结【点击

||->NSCoding & NSCoder仅有的两个方法,数据的序列号和反序列化【点击

||- (void)encodeWithCoder:(NSCoder *)aCoder;

||- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;

||->NSCopying & NSZone

||+ (instancetype)allocWithZone:深拷贝,类似于memcpy这样的C方法【点击

||->NSAutoreleasePool

||降低内存峰值【点击

||->NSFileManager删除文件的时候先判断是否存在是个好习惯

||->NSTimer

||NSTimer 简单使用【点击】

||NSTimer定时器时间并不精确,类似于公交车进站,堵车就不准时【点击】

||->NSLog暴力打印,常用于测试【点击

||->NSClassFromString从字符串获取类。NSStringFromClass,从类名获取字符串

||不要小瞧这两个API,配合使用,他可以做到代码逻辑解藕的效果。

|/

|->Foundation

|

||->NSIndexPath链式结构;tableview用的比较多【点击】

||初始化 [NSIndexPath indexPathForRow:0 inSection:1];

||->NSError网络变成经常用到

||->NSException

||->NSStringEncoding NSString的编码格式,了解即可【点击

||->NSProgressIndicator

||->NSBundle 是个目录,包含了程序使用的资源,如图像,声音,编译好的代码,nib文件【点击】

||->NSNetServiceBrowser

||->NSValue可以包装任意一个对象,可以用NSValue将struct存到NSArray和NSDictionary中。【点击】

||->NSURLConnectioniOS9已不再使用

||->NSURLSession&NSURLSessionTask点击】NSURLSession提供的功能:

||通过URL将数据下载到内存【点击】

||通过URL将数据下载到文件系统

||将数据上传到指定URL

||在后台完成上述功能【点击】

||->NSURLRequest 包装了网络请求的信息【点击】

||->NSInputStream & NSOutputStream socket编程【点击】

||->NSPredicate

||谓语查询,原理和用法都类似于SQL中的where【点击

||->NSLayoutConstraint

||->NSLock & NSRecursiveLock & NSCondition多线程锁

||最基本的同步锁【点击

||@synchronized{//todo} 同样也是同步锁【点击】

||事实上信号量也能实现锁的目的,信号量和锁的区别【点击】第二篇【点击

||->NSMethodSignature

/|配合NSInvocation实现消息转发【点击】

iOS|->NSInvocation直接调用 某个对象的消息【点击】

|iOS中可以直接调用 某个对象的消息 方式有2种performSelector:withObject: 和NSInvocation

||当然,还以用C语言的函数指针,参见下面的“方法调配技术

||->NSSet无序的对象集合,用处少

||->NSUrl基本使用,包含File URL和File path【点击

||->AVPlayer基本使用【点击】

||获取视频时间长度【点击】

|->NSNotificationCenter同步的机制【点击】注意防止重复,相似的机制还有delegate,observer,block

|

|/->创建push原理介绍、证书制作、测试push 专辑【点击】

||“iOS push全方位解析(一)【译文】”——iOS PUSH概述【点击

||“iOS push全方位解析(二)【译文】”——生成OpenSSL证书,Provisioning Profile【点击】

||“iOS push全方位解析(三)【译文】”——一个极简的demo,并测试一下push【点击】

|/

|->Push

|

||★iOS6、7、8、9 Push的演化【点击】,但目前还是不尽人意(APP 无法获取通知栏消息数目)

||php写的可以在本机发送iOS push程序【点击】

||iOS7 Background Remote Notification(后台远程通知——静默push)【点击】

|->有一些三方push SDK:极光push

|

|->block必须掌握

|block专辑【点击】;Block带有局部变量的匿名函数;iOS开发尤其实用

|【block编程第一篇】 block编程热点介绍(官方文档翻译的)【点击

|【block编程第二篇】 block捕获变量和对象【点击

|【block编程第三篇】block内存管理——如何验证block在栈上,还是堆上【点击】

|【block编程第四篇】block的实现【点击

|【block编程第五篇】block中使用 weak–strong dance 技术避免循环引用【点击

|->多线程

|iOS有三种多线程编程的技术,分别是:【点击

|1、NSThread 下面会讲到

|2、Cocoa NSOperation 下面会讲到

|3、GCD 下面会讲到

|这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单。

|dispatch_once 执行一次,用于创建单例【点击】可满足线程安全

|iOS 不像C++ 那样,可以直接将构造函数设成private所以创建绝对单例模型需重写allocWithZone,【点击

|

|/->引用计数(retainCount)

||retain 引用计数+1 对象alloc时,引用计数为1, release引用计数-1.引用计数=0时候,真正释放

||autoRelease,自动释放对象【点击

||->便捷构造方法 iOS

||对象在自动释放池中,不需要开发者手动释放,比如下面的方法

||NSString的stringWithString

||NSArray的arrayWithObjects:和arrayWithArray:

||UIImage的imageNamed:

||->内存管理高级指南【官方译点击

||->内存管理实践点击

|/

|->内存管理【专栏点击

|

||->MRC手动引用计数。release和retain成对儿

|->ARC自动引用计数

|强烈建议使用ARC

|禁止在函数内返回局部变量指针,不然就是野指针!

|★容易引起循环引用的地方【点击

|★- (id)performSelector:(SEL)aSelector withObject:(id)object;引起警告

|warning:performSelector may cause a leak because its selector【点击

|

|->进程间通信(APP间通信)点击】【点击

|iOS可通过URL Scheme,调用别的APP(iOS内的应用调用协议),APP 实现 - (BOOL)application: openURL: options:

|

|/->Runtime运行时特点【《运行时之一:类与对象》南峰子出品点击

||Objective-C程序员可以在程序运行时创建,检 查,修改类,对象和它们的方法【点击

||Objective-C runtime库也负责找出方法的最终执行代码

||class  Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。

||struct objc_class {

||Class isa  OBJC_ISA_AVAILABILITY;

||#if !__OBJC2__

||Class super_class                       OBJC2_UNAVAILABLE;  // 父类

||const char *name                        OBJC2_UNAVAILABLE;  // 类名

||long version                                 OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0

||long info                              OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识

||long instance_size                       OBJC2_UNAVAILABLE;  // 该类的实例变量大小

||struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表

||struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表

||struct objc_cache *cacheOBJC2_UNAVAILABLE;  // 方法缓存

||struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表

||#endif

||} OBJC2_UNAVAILABLE;

||1.isa:所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass

||2.super_class:指向该类的父类,如果该类已经是最顶层的根类,则super_class为NULL。

||3.cache:用于缓存最近使用的方法。提高方法查找效率

||objc_object与idobjc_object是表示一个类的实例的结构体

||struct objc_object {

||Class isa  OBJC_ISA_AVAILABILITY;

||};

||typedef struct objc_object *id;

||当创建一个类的实例对象时,分配的内存包含objc_object数据结构,然后是类的实例变量的数据。

||NSObject类的alloc和allocWithZone:方法使用函数class_createInstance来创建objc_object数据结构。

||另外还有我们常见的id,它是一个objc_object结构类型的指针

||meta class元类,是一个类对象的类;它存储着一个类的所有类方法。

||当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;

||而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。

||★继承体系【点击

||动态创建类【点击

||objc_setAssociatedObject【点击】给对象增加属性,一般配合类别使用

||object_getClass  得到一个实例的类【点击

||objc_copyImageNames  获取指定类所在动态库【南峰子出品点击

||objc_copyClassList  创建并返回一个指向所有已注册类的指针列表【点击

||class_xxx系列函数【点击

||class_copyPropertyList  获取类的属性

||class_addMethod 为类添加方法

||class_isMetaClass 判断是否为元类

||class_getName 获取类名

||class_copyIvarList 拷贝类的实例变量列表

||class_getInstanceMethod 获取实例方法

||->Runnloop【ibireme出品点击

||RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息

||并提供了一个入口函数来执行上面 Event Loop 的逻辑

||Run Loop并非iOS平台专属的概念,在任何平台的多线程编程中,为控制线程生命周期【点击

||接收处理异步消息,都需要类似Run Loop的循环机制来实现:从简单的一个无限顺序

||do{sleep(1);//执行消息}while(true),到高级平台,如Android的Looper,都是类似的机制。

||PerformSelecter 当调用 NSObject 的 performSelecter:afterDelay: 后,实际上其内部会创建一个 Timer

||并添加到当前线程的 RunLoop 中;所以如果当前线程没有 RunLoop,则这个方法会失效【点击

|/

|->iOS 动态机制

|

||->消息传递objc_msgSend【点击】【南峰子出品点击】

||obj-c脱胎于smalltalk的消息处理。所有方法调用都是发消息。消息是啥?一串字符【点击

||如果向某对象传递消息,那就会使用动态绑定机制来决定需要调用的方法

||objc_msgSend有两个隐藏参数,消息接收对象 方法的selector ,即(self,_cmd)

||->消息转发message forwarding【点击】

||就是对象在接收到无法解读的消息之后会发生什么情况

||(1) +(BOOL) resolveInstanceMethod:(SEL)selector 类是否新增一个实例方法

||(2) resolveClassMethod 是否新增了类方法

||(3) -(id) forwardingTargetForSelector:(SEL)selector 能不能把这条消息转给其他接收者来注册

||(4)-(void) forwardInvocation:(NSInvocation*)invocation  消息派发系统

||(5)最后若都不能处理消息,则doesNotRecognizeSelector: 会抛出异常

||当我们不能确定一个对象是否能接收某个消息时,会先调用respondsToSelector:来判断一下

||->SEL【点击

||SEL又叫选择器,是表示一个方法的selector的指针,每一个方法都对应着一个SEL。

||OC在编译的时候,会根据方法的名字(包括参数序列),生成一个用 来区分这个方法的唯一的一个ID

||这个ID就是SEL类型的。需要注意的是,只要方法的名字(包括参数序列)相同,那么它们的ID都是相同的。

||就是 说,不管是超类还是子类,不管是有没有超类和子类的关系,只要名字相同那么ID就是一样的

||方法的定义体里面,我们可以通过访问_cmd得到这个方法自己的SEL。

||->方法调配技术method swizzling 用于调试【南峰子出品点击】

||IMP 它是objetive-C 方法(method)实现代码块的地址,实际上是函数指针,指向方法实现的首地址

||IMP imp = [requestItem.delegateTarget methodForSelector:selector];

||void (*func)(id, SEL, ResponseItem *) = (void *)imp;

||func(requestItem.delegateTarget, selector, responseItem);

||可以从selector获取IMP,比如:- (IMP)methodForSelector:(SEL)aSelector;

||Swizzling应该总是在+load中执行

|->事件响应链点击】另外一篇【点击

|在 iOS 中,几乎所有类都是 responder,比如 UIWindow、UIView、UIControl、UIControllers 等

|当手指去触摸屏幕上 UIView 的实例对象 aView。产生一个触摸事件 UIEventTypeTouches

|而接收触摸事件的对象 aView,就是一个 responder object。

|initial view –> super view –> …..–> view controller –> window –> Application –> AppDelegate

|

|/->沙盒(Sandbox)iOS沙盒机制【容芳志出品点击

||每个应用程序都有自己的存储空间

||应用程序不能翻过自己的围墙去访问别的存储空间的内容

||应用程序请求的数据都要通过权限检测,假如不符合条件的话,不会被放行。

||->GroupiOS8+数据共享,例如扩展(Extension)共享数据【点击

||->SpotlightiOS9+ 系统搜索。【官方demo点击

||->GCD(Grand Central Dispatch)iOS开发有一个强有力的多线程工具【点击

||多线程入门【raywenderlich出品点击】

||系统提供一个叫做 主队列(main queue)

||系统还提供一个叫做全局调度队列(Global Dispatch Queues)有四个优先级

||开发者自己创建队列(串行,或者并行)

||★至少有五个队列任你处置:主队列、四个全局调度队列,再加上任何你自己创建的队列。

||GCD 深入理解:第一部分【点击】

||GCD 深入理解:第二部分【点击】

||开发常见方法介绍

||dispatch_after 延后工作

||Dispatch Groups 会在整个组的任务都完成时通知你

||dispatch_semaphore_t  信号量,让你控制多个消费者对有限数量资源的访问。【点击

||dispatch_semaphore_wait  使得信号量-1,当=0时候阻塞

||dispatch_semaphore_signal  释放信号量,即信号量+1

||

||->CoreData数据持久化,相比sqlite有下面优势【点击

||数据库字段或者表有更改会导致crash,CoreData的版本管理和数据迁移变得非常有用,

||手动写sql语句操作还是麻烦一些。

||不光能操纵SQLite,CoreData和iCloud的结合也很好,如果有这方面需求的话优先考虑

||并不是直接操纵数据库,比如:使用CoreData时不能设置数据库的主键,目前仍需要手动操作。

||效率上其实跑程序时感觉不出来,毕竟手机上的数据不能跟网站的数据和访问量相提并论。

|/

|->特殊封装&平台特性

|

||->类别(Category)扩展(Extension)微小区别【点击】

||堪称iOS编程的精髓【点击】念茜出品【点击

||->KVC键值编码

||在IOS的中,没有绝对的私有,包括方法和变量,可以通过字符获取属性【点击】

||->KVO键值观察,依赖isa-swizzling技术【王中周出品点击

||依赖Runtime 和KVC 一个新的类会动态被创建。详细原理【点击】另外一篇【点击】

||同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。

||然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,

||因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制

||Person在建立KVO监听前和之后的打印输出 self->isa:Person    [self class]:Person

||self->isa:NSKVONotifying_Person   [self class]:Person

||★比如:Tableview上拉下拉动画检测offset;播放视频,获取视频时长时候等

||为什么KVO不成对儿调用,会崩溃?

||->多任务

||后台运行一段时间(不是地图,voip类app)【点击

||->3D Touch,通过在plist中添加菜单,然后app实现下面的方法。进入APP

||- (void)application: performActionForShortcutItem: completionHandler:

||->spotlight通过系统搜索,进入APP【点击

|->Touch ID如何使用iOS 8 指纹识别,代码、实例【点击

|->HTTPs

|建立安全链接【点击

|https进阶【点击

|

->iOS工具

CrashHlytics Crash统计工具

AFNetworking 和 ASIHttp

SDImage

TMCache

AsyncDisplayKit 是 Facebook 推出的用于保持界面流畅性的框架

——————————————————————————————

参考文献:《Objective-C高级编程:iOS与OS X多线程和内存管理》日本人写的;

《Effective Objective C 2.0:编写高质量iOS与OS X代码的52个有效方法》;

《Objective-C基础教程(第2版)》

网络博客参考(无循序):念茜、南峰子、ibireme、容芳志、唐巧、王巍、董柏然、阮一峰、一片枫叶,王中周,颐和园等博主

参考的公众帐号:《iOSDevTips》

完整的UIKit和Foundation 结构 <点击>

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

推荐阅读更多精彩内容