ios 面试题


1.Foundation对象与Core Foundation对象有什么区别

  1. Foundation对象是OC的,Core Foundation对象是C对象
  2. 数据类型之间的转换
  • ARC:__bridge_retained、__bridge_transfer
  • 非ARC: __bridge
Snip20180509_1.png

2.KVO内部实现原理

  • 1.KVO是基于runtime机制实现的
  • 2.当某个类的对象第一次被观察时, 系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。 派生类在被重写的 setter 方法实现真正的通知机制(NSKVONotifying_Dog)。我们注册监听的时候,底层找方法的的isa指针就变成指向新创建的子类对象也就是NSKVONotifying_Dog这个新类。


    Snip20180509_4.png
派生出的问题:
1.为什么用的是子类而不是分类?

答:因为如果用分类的话,那么Dog的子类就不走了,肯定不行。

2.你可否自己实现kvo?

答:kvo是给予runtime机制的。具体的请点击
https://blog.csdn.net/u014247354/article/details/78403567

3.kvo的局限性?

答:kvo只能监听属性的改变;再一个,运行时时创建派生类比较耗性能。


3.手写单例

#import "MMTool.h"

@implementation MMTool
static MMTool *_mmTool = nil;
+(instancetype)allocWithZone:(struct _NSZone *)zone{
    if (_mmTool == nil) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _mmTool = [super allocWithZone:zone];
        });
    }
  
    return _mmTool;
}
+(instancetype)sharedMMTool{
    return [[self alloc]init];
}

4.runtime

1.必备常识
  • Ivar : 成员变量
  • Method : 成员方法
  • objc_msgSend : 给对象发送消息
  • class_copyMethodList : 遍历某个类所有的方法
  • class_copyIvarList : 遍历某个类所有的成员变量

5.关于block

下面是面试题:

  1.
    int a = 10;
    void (^block)() =^{
        NSLog(@"打印结果是 %d",a);   
    };
    a = 20;
    block(); //打印结果是 10
----------------------------------------------------------------------------
 2.
   static int a = 10;
    void (^block)() =^{
        NSLog(@"打印结果是 %d",a); 
    };
    a = 20;
    block(); //打印结果是 20
----------------------------------------------------------------------------
3.
 __block int a = 10;
    void (^block)() =^{
        NSLog(@"打印结果是 %d",a); 
    };
    a = 20;
    block(); //打印结果是 20
----------------------------------------------------------------------------
4.
 int a = 10;
- (void)tes{
    void (^block)() =^{
        NSLog(@"打印结果是 %d",a); 
    };
    a = 20;
    block(); //打印结果是 20   
}
除了第一种是值传递之外,剩下的只要有修饰(__block、static)、或者全局变量修饰的都是指针传递。
用static修饰、和一个全局变量,本质是一份内存,所以是指针传递,也就是内存地址传递。前后的内存地址是一样的
用__block修饰,其本质是:会把“外部变量”在栈中内存地址放到堆中。前后的内存地址不一样
除了第一种不能在block中修改a的值,剩下的三种都是可以修改a的值。

1.在用__block修饰的时候,是把“外部变量”在栈中内存地址放到堆中,所以当我们修改a的值的时候,其实是在栈去进行修改。
2.而不用__block修饰的时候,再去修改a的值,那就是在栈中进行修改,然后就会报错。

所以:栈中的数据不能修改,内存由系统释放。堆中的数据可以修改,所以想修改,就用__block修饰。


关于block的循环引用问题:

block用从copy修饰。那么内存就在堆区,copy一次,就会retain,引用对象的计数器就会加1. 所以用block就用__block(MRC);
ARC :id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self该方法可以设置宏。
就可以保证对象在block中引用的时候,引用计数器不会增加。

关于block【RAC中的一个例子】

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}
(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe 

RACDisposable * :是返回值类型  
id<RACSubscriber> subscriber:指的是传入的参数
didSubscribe : block起的别名


6.关于MRC开发

原则:
  • 有alloc\init\copy的,都要对应的使用release或者autorelease
  • 有retain的都要使用一次release或者autorelease。
.h文件:
@property (retain, nonatomic) Dog * dog;
@end
@implementation Person
- (void)setDog:(Dog *)dog{
    if (_dog != dog) {
        [_dog release]; //开始指向空指针,给空指针发消息是OK的
        [_dog retain]; //引用计数加一,然后_dog = dog
    }
}

- (void)dealloc{
    [self.dog release];
    self.dog = nil;
    [super dealloc];
}
@end
在dealloc方法里面为什么要进行release? 在set为什么要判断_dog!=dog?然后再release再retain?

答:在dealloc里面release 是因为,对dog对象进行了retain,所以要release。

解释set方法

如果没有if判断

p.dog = dog1;
p.dog = dog1;
[d release]
p.dog = dog1;  //这句就会崩溃,因为dog1的引用计数为0。
加了判断后,意思就是:如果是同一对象,那么就不管。如果是新对象,那么就释放旧对象然后对新对象retain一次。

7.多线程的底层实现?

1.首先弄清楚什么是线程,什么是多线程。
2.Mach是第一个以多线程方式处理任务的系统,因此多线程的底层实现机制是基于Mach的线程
3.开发中很少用Mach级的线程,因为Mach级的线程没有提供多线程的基本特征,线程之间是独立的

开发中实现多线程的方案

1.C语言的POSIX接口:#include <pthread.h>
2.OC的NSThread
3.C语言的GCD接口(性能最好,代码更精简)
4.OC的NSOperation和NSOperationQueue(基于GCD)

线程间怎么通信?

1.performSelector:onThread:withObject:waitUntilDone:
2.NSMachPort

8.网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?

利用字典(图片地址为key,下载操作为value)

/**定义字典保存下载好的图片key 图片的地址 value 图片UIImage*/
@property (nonatomic, strong) NSMutableDictionary *imagesDic;

/**定义字典保存下载操作key 图片地址 value 下载操作*/
@property (nonatomic, strong) NSMutableDictionary *operationsDic;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}

// 1.根据下载地址去字典中取图片
UIImage *image = self.imagesDic[@"http://www.baidu/example.png""];

// 2.判断字典中是否有图片(是否已经下载过图片)
if (image == nil) {
    // 没有下载过(1.从来没有下载过, 2.没有下载完,正在下载中)
    
    NSOperation *operation =self.operationsDic[@"http://www.baidu/example.png"];
    if (operation == nil) {
        // 1.从来没有下载过
        // 创建操作
        operation = [NSBlockOperation blockOperationWithBlock:^{
            NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.baidu/example.png"]];
            UIImage *image = [UIImage imageWithData:imageData];
            
            // 将下载好的图片存储到字典中
            self.imagesDic[@"http://www.baidu/example.png""] = image;
            
            // 将操作从字典中移除
            self.operationsDic[@"http://www.baidu/example.png""] = nil;
            
            // 回到主线程更新UI
            dispatch_async(dispatch_get_main_queue(), ^{
                cell.imageView.image = image;
            });
        }];
        // 将操作放入队列,会自动开辟一个线程
        [self.queue addOperation:operation];
 
        // 将操作添加到字典中,这里可以用来判断是不是正在下载
        self.operationsDic[@"http://www.baidu/example.png"] = operation;
        
    }else
    {
        // 2.没有下载完,正在下载中
        cell.imageView.image = [UIImage imageNamed:@"占位图片"];
    }
}else
{
    // 已经下载过
    cell.imageView.image = image;
}
return cell;
}
思路
Snip20180511_1.png
9.你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

1.GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
2.GCD只支持FIFO的队列,NSOperationQueue可以很方便地调整执行顺序、设置最大并发数量、依赖、栅栏
3.NSOperationQueue可以在轻松在Operation间设置依赖关系,而GCD需要写很多的代码才能实现
4.NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
5.GCD的执行速度比NSOperationQueue快

  • 任务之间不太互相依赖:GCD
  • 任务之间有依赖\或者要监听任务的执行情况:NSOperationQueue
10.使用 [UIImage imageNamed:@"example.png"];会有怎样的影响?

imageNamed加载图片
1.用 imageNamed:方法加载的图片不会随着UIImageView一起销毁,而是依旧在内存中。【用instrument实时看的】
2.加载时耗的内存比较大
3.相同的图片只会加载一份到内存中,如果使用多次或者同时使用,使用的是同一个对象。

imageWithContentsOfFile加载图片
1.用 imageWithContentsOfFile:方法加载的图片会随着UIImageView一起销毁
2.加载时耗的内存相对于imageNamed方法要小
3相同的图片会多次加载到内存中 ,如果同时使用,使用的是不同的对象。

  • 总结:imageNamed:如果一些图片在多个界面会使用,并且图片较小、使用频率高。例如:图标和小的背景图。
  • imageWithContentsOfFile:只在一个地方用、并且图片较大、使用频率不高。

11.关于self和super关键字

Self关键字
1.如果self在对象方法中,那么self就代表调用当前对象方法的那个对象
2.如果self在类方法中,那么self就代表调用当前类方法的那个类。
总结:我们只关注self 在哪个方法中。
Super关键字
1.如果想在子类方法中调用父类的方法,就可以用super。
2. super 是一个 Magic Keyword, 它本质是一个编译器标示符,super 会告诉编译器,调用 class 这个方法时,要去父类的方法,而不是本类里的。

  • 一个面试题
 下面的代码输出什么?
@implementation Son : Father
- (id)init
{
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end
都输出 Son
NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son
解释:https://www.jianshu.com/p/10b65df06e44

1.[self class]的意思是先去子类中找class方法;[super class]的意思是先去Father父类中找class方法;
2.[self class]没有找到,最后找到NSObject里面找到class方法,而 - (Class)class的实现就是返回self的类别,故上述输出结果为 Son。[super class]也是一样,最后也在NSObject里面找到class方法...

  • 如果改成这样
@implementation Son : Father
- (id)init
{
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end
-----------------------------------------
@implementation Father
- (Class)class{
    [super class];
    return  [Father class];
}
@end
都输出 Father
NSStringFromClass([self class]) = Father
NSStringFromClass([super class]) = Father

但如果改成这样子:

@implementation Son
- (id)init
{
    self = [super init];
    if (self) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
- (Class)class{
    [super class];
    return  [Son class];
}
@implementation Father
//空的
@end
都输出 Son
NSStringFromClass([self class]) = Son
NSStringFromClass([super class]) = Son

12.New实现原理

New做了三件事情

1.开辟存储空间 +alloc方法
2.初始化所有的属性(成员变量)- init 方法
3.返回对象的地址


如图:


Snip20180516_8.png

13.什么是构造方法?什么是类构造方法?;instancetype和id的区别?

构造方法
- (instancetype)init{
    if (self = [super init]) {
        
    }
类构造方法
+(instancetype)person{
    return [[self alloc]init]; //这里一定要用self不要用类名。
}
//id 是动态类型,在运行的时候才会确定具体的类型;instancetype是静态类型,在编译时就确定具体的类型。
有了id动态类型,便于多态的使用。

14.类的本质和存储细节?

Snip20180517_3.png

15.类的启动过程?

1.先调用+ (void)load{}
只要程序启动就会将类的代码加载到内存中,放到代码区【只要程序启动就加载而不是用到的时候加载】load方法会在当前类被加载到内存的时候调用,有且仅会调用一次
2.再调用+ (void)initialize{ },在当前类第一次被使用时就会调用(创建类对象的时候,类对象只会创建一次)。这个方法在整个程序中只调用一次。

注意点:
1.如果有继承关系,则先调用父类的load方法
2.如果有继承关系,则先调用父类的initialize方法

f#16.空指针和野指针以及僵尸对象?

image.png

即指向僵尸对象的指针就是野指针

@autoreleasepool {
        Person * p = [[Person alloc]init];
        [p release];//0 这个时候堆类的实例对象就是一个僵尸对象

        [p release]; //p 这个时候调用release的时候,实例对象已经被销毁,这个时候会崩溃。这个时候p就是野指针【即指向僵尸对象的指针就是野指针】
        [p release];
        [p release];
    }
上面代码会崩溃
改成
@autoreleasepool {
        Person * p = [[Person alloc]init];
        [p release];
        p = nil; //让p指向空指针,给空指针发消息是OK的
        [p release]; 
        [p release];
        [p release];
    }

17.关于@class和import, 以及@class避免的循环拷贝?

1.import是一个预编译指令,它会将“.h”文件拷贝到import所在的位置,并且import有一个特点,只要".h"中的文件发生了变化,那么importj就会重新拷贝一次(更新操作)。【如果A中import了B类,B中import了C类,C类一动,B和A类都会改动】
2.@class仅仅只会告诉编译器,@class后面是一个类,所以编译器不知到这个类中有什么方法和参数。所以在.m文件里面需要import,这个时候如果改变导入的类,只会更新引用的这个类,而不是很多类。


image.png

18.关于循环retain

image.png
    Person * p = [[Person alloc]init];
    Dog * d = [[Dog alloc]init];

    p.dog = d; //2
    d.ownner = p; //2

    [p release];//1
    [d release]; //1
解决就让某一方不要进行retain,改成
'@property (strong, assign)Person  * owner;'改成assign。

19.关于autorelease和autoreleasepool

1. [p autorelease] 引用计数是不变的。
这句话的意思是:系统会创建一个自动释放池。当自动释放池销毁的时候会给自动释放池里面的对象发送一次release。相当于延迟release

    @autoreleasepool {
    Person * p = [[Person alloc]init];
    [p run];
    [p release];
    [p run]; //这句话崩溃
}
    @autoreleasepool {
    Person * p = [[Person alloc]init];
    [p run];
    [p autorelease]; //这句话的好处是,我们不用关心什么时候释放。会在最后统一发一次release
    [p run]; 但是这个不会。
}
注意点:

1.一定要在 @autoreleasepool {
}里面进行autorelease。
2.在@autoreleasepool {
}不要进行消耗内存的操作
3.自动释放池是可以嵌套的。

20.关于Copy的深浅拷贝和copy的内存管理;以及property和copy;以及block为什么用copy修饰;以及自定义类实现copy。

原则:

  • copy会产生一个新的副本,修改副本不会影响原来的值,修改原本也不会影响副本的值。
浅拷贝:就是指针拷贝。
深拷贝:就是创建新对象。

如果前后两个对象是不可变的,就是浅拷贝。其他的都是深拷贝。
举例:

 NSString * str = @"qwe";
 NSString * strCopy  =[str copy];  //浅拷贝。要满足我们的原则。
总结:浅拷贝不生成新的对象。深拷贝会产生新的对象

所以浅拷贝会进行一次retain


property和copy

防止外界修改内部的值

@property (nonatomic, copy) NSString * str;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
  
   NSMutableString * s = [NSMutableString stringWithFormat:@"hello"];
    _str = s;
    [s appendString:@"world"];
    NSLog(@"str = %@  , s = %@",_str,s);
}
打印结果:str = helloworld  , s = helloworld
原因是copy执行的是深拷贝。生成了一个新的str对象。
所以字符串就用copy修饰

block为什么用copy修饰

因为block默认在栈中,就不会对外界对象进行retain ,若在block中访问对象,但是对象在访问前就被释放了就会崩溃。所以用copy,将block从栈中移到堆中,这样就可以retain一次,保要使用对象的命。

自定义类实现copy

1.遵守NSCopying协议
2.实现- (id)copyWithZone:(NSZone *)zone{
}

21.关于网络?

1.什么是URL?

URL的全称是Uniform Resource Locator(统一资源定位符)
通过1个URL,能找到互联网上唯一的1个资源
URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL.

URL的基本格式 = 协议://主机地址/路径
http://202.108.22.5/img/bdlogo.gif

2.什么是请求头、请求体,什么是响应头、响应体 ?

请求头:包含了对客户端的环境描述、客户端请求信息等

image.png
image.png

22.小知识点

[UINavigationBar appearance];
[UITabBarItem appearance];
通过appearance统一设置所有UITabBarItem的文字属性
后面带有UI_APPEARANCE_SELECTOR的方法, 都可以通过appearance对象来统一设置

23.内存泄漏的种类,以及你是如何避免的?

参考文章1
参考文章2
1.网络请求管理者。保持是一个管理者,如果多个管理者就有多个任务队列。
2.Block的循环引用。
3.delegate的循环引用
4.#import的循环引用
5.无线for循环 最后内存飙升,APP崩溃
6.NSTimer不清除会内存泄露。手机发烫,内存飙升app崩溃。
7.局部变量是控制器,它被释放后,其View还在,这个时候也是内存泄露。

避免:
1.运用单例
2.__weak typeof(self) weakSelf = self;
3.weak 或者assign
4.用@class
5.用instruments看内存增长的情况
6.dealloc的时候清楚NSTimer
7.运用父子控制器,再一个用strong修饰,不用局部变量。

24.谈谈上拉下拉刷新的细节处理?

1.这里主要涉及的是多次请求问题
2.请求失败情况下的问题。
3.刷新控件的关闭和显示问题
4.分页处理的问题,page参数的恢复问题。

25.一些开发经验?

1.如果图片设置的frame与预设的不一样,要想到autoresizing
2.减轻第三方框架的风险。对第三方框架进行一次封装,面向自己的类开发。

26.frame和bounds,为什么要有bounds?

bounds的有以下两个特点,可以从bounds自身的来剖析:bounds是一个Rectangle,前半部分是point后半部分是view的size。这两个属性也预示着两个特点:

bounds像是浮于frame之上的。frame是一个框架,bounds是显示子view的东西,下面总结bounds的两个特征:

第一、 对于bound的point:它不会改变frame的原点,改变的是bounds自己的原点,进而影响到“子view”的显示位置。这个作用更像是移动bounds原点的意思。
第二、 对于bound的size:它可以改变的frame。如果bounds的size比frame的size大。那么frame也会跟着变大,那么frame的原点也会变,但是center不会变。这个作用更像边界的意思。
可以推测一下,setBound第一个特性可以用于view的滑动,手势动作,因为可以影响子view的显示位置。
工程中经常修改tablewview的contentInset值。该技巧常用于屏幕两边,上下头部的“留白”。修改contentInset的时候其实修改的也是bounds。

27.ARC的实现机制到底是什么?

ARC 的工作原理大致是这样:当我们编译源码的时候,编译器会分析源码中每个对象的生命周期,然后基于这些对象的生命周期,来添加相应的引用计数操作代码。所以,ARC 是工作在编译期的一种技术方案,这样的好处是:

编译之后,ARC 与非 ARC 代码是没有什么差别的,所以二者可以在源码中共存。实际上,你可以通过编译参数 -fno-objc-arc 来关闭部分源代码的 ARC 特性。

28.SDWebimage的缓存策略是什么?

29.iOS开发中#import、#include和@class的区别解析

  1. 一般来说,导入objective c的头文件时用#import,包含c/c++头文件时用#include。
  2. ,#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。<标记>
    所以,#import比起#include的好处就是不会引起交叉编译。

,#import && #class:

  1. import会包含这个类的所有信息,包括实体变量和方法(.h文件中),而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,后面会再告诉你。
  2. 在头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
    备注:#import 就是把被引用类的头文件走一遍,即把.h文件里的变量和方法包含进来一次,且仅一次,而@class不用,所以后者编译效率更高。
  3. 在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。
  4. 如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
    备注:实践证明,A,B相互#import不会出现编译错误。因为<标记>处已经说明#import时文件只被导入一次,所以此条不成立。
    总结:
  5. 如果不是c/c++,尽量用#import。
  6. 能在实现文件中#import,就不在头文件中#import。
  7. 能在头文件中@class+实现文件中#import,就不在头文件中#import。

30.NSDictionary 的底层数据结构是什么?

NSDictionary(字典)是使用 hash表来实现key和value之间的映射和存储的, hash函数设计的好坏影响着数据的查找访问效率。数据在hash表中分布的越均匀,其访问效率越高。而在Objective-C中,通常都是利用NSString 来作为键值,其内部使用的hash函数也是通过使用 NSString对象作为键值来保证数据的各个节点在hash表中均匀分布。
参考文章

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

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,044评论 29 470
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类...
    司马DE晴空阅读 1,234评论 0 7
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,042评论 1 32
  • 把网上的一些结合自己面试时遇到的面试题总结了一下,以后有新的还会再加进来。 1. OC 的理解与特性 OC 作为一...
    AlaricMurray阅读 2,483评论 0 20
  • 2018-05-26 晴 昨日早上,我像往常一样早起,听英语,做饭,送孩子,然后去上班。婆婆也像往常一样比我晚点...
    周舟阅读与写作阅读 161评论 0 1