iOS高级开发面试题

iOS面试题目100道

1.线程和进程的区别。

        进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位。线程基本不拥有系统资源,拥有自己的栈空间,它与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程。同一个进程中的多个线程之间可以并发执行。

        进程和线程的主要差别在于他们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响,线程知识一个进程中的不同执行路径,有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。

一个程序至少有一个进程,一个进程至少有一个线程。

线程的划分尺度小于进程,使得多线程程序的并发性高,多个线程共享内存,极大提到了程序的运行效率。

线程不能独立执行,必须已存在应用程序中,由应用程序提供多个线程执行控制。

进程是资源分配的基本单位,线程是调度的基本单位,因为线程小,调度开销就小,所以效率高。

多线程的意义在于一个应用程序中,有多个执行部分可以同时之星。但操作系统并没有将多个线程看做多个独立的应用

线程执行开销小,但不利于资源的管理和保护

2.定义一个NSString类型属性时,为什么用copy不用strong?

这个NSString类型属性是一个指针,定义成copy,操作是拷贝一份等同的对象,这个指针指向新生成的拷贝对象。当使用copy时,这个拷贝的对象无论是拷贝自NSString还是NSMutableString结果都是不可变的NSString。而如果用Strong,则指向一个字符串对象,若指向的是一个NSMutableString,则当指向的对象改变时,属性值也会发生相应改变,导致错误,因为是一个不可变字符串

3.应用多线程的时候会出现什么问题,应如何避免问题的发生?

多线程容易导致资源争抢,发生死锁现象.死锁通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在相互等待,造成了无法执行的情况。 

避免死锁的一个通用的经验法则是:当几个线程都要访问共享资源A、B、C时,保证使每个线程都按照同样的顺序去访问它们,比如都先访问A,在访问B和C

采用GCD中的栅栏方法,用并行队列去装载事件并异步去执行。

4.应用循环是怎么产生的,如何解决引用循环。

两个类中有属性分别为彼此的实例,这样就会引发循环应用。 

使用block、NSTimer时也很容易导致循环应用.设置一个应用为弱引用既可以解决强应用循环。

5.NSTimer使用中的注意事项

在类中定义定时器并把目标对象设置为self时,所以NSTimer实例会保存此实例,但定时器是用在类中用实例变量存放的,所以此实例也保留了定时器,这就造就了循环应用。除非调用invalidate方法并把定时器设置为nil,或者系统回收实例,才能打破循环应用,如果无法确保stop一定被调用,就极易造成内存泄露。

使用block可以防止NSTimer导致的内存泄露.

在NSTimer分类中定义方法,让NSTimer的target为NSTimer实例本身,然后block从类实例中copy一份,在NSTimer中定义方法去执行拷贝的block。在uerInfo中去放block的拷贝。

6.App都有哪些运行状态?

状态:未运行,未激活,激活,后台,挂起。

未运行:程序未启动 

未激活:程序在前台运行,不过没有接受到事件。 

激活:程序在前台运行且受到了事件。 

后台:程序在后台而且能执行代码,大多程序进入这个状态后会在这个状态停留一会,时间到之后会进入挂起状态。 

挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中,系统内存低时,系统就把挂起的程序清除掉。

各个程序运行状态时代理的回调:

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

      告诉代理进程启动但还没进入状态保存

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    告诉代理启动基本完成程序准备开始运行

- (void)applicationWillResignActive:(UIApplication *)application

    当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了

- (void)applicationDidBecomeActive:(UIApplication *)application

    当应用程序入活动状态执行,这个刚好跟上面那个方法相反

- (void)applicationDidEnterBackground:(UIApplication *)application

    当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可

- (void)applicationWillEnterForeground:(UIApplication *)application

    当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。

- (void)applicationWillTerminate:(UIApplication *)application

    当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。

- (void)applicationDidFinishLaunching:(UIApplication*)application

    当程序载入后执行

7.栈、堆、静态区域的区别

OC中,非对象的变量都存在栈中,对象都存在堆中,静态区域的内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,主要存放静态数据、全局数据和常量。

栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存效率高,内存容量有限。

堆区:OC对象存储于堆中,当对象的应用计数为0时自动释放该对象。

8.子视图超出父视图的部分能看到么?超出的部分有什么影响?

子视图超出父视图的部分能看到。但是超出的部分不能响应事件

想让超出的部分响应事件,就该写父视图的hitTest方法。判断触碰区域是否在子视图内,如果在子视图内,则返回子视图。让子视图去响应事件。

9.respond链是如何响应的,响应顺序是怎样的?

在iOS系统中,能够响应并处理事件的对象称之为responder object, UIResponder是所有responder对象的基类,在UIResponder类中定义了处理各种事件,包括触摸事件(Touch Event)、运动事件(Motion Event)和远程控制事件(Remote-Control Events)的编程接口,

UIApplication, UIViewController,UIView和所有继承自UIView的UIKit类(包括UIWindow,继承自UIView)都直接或间接的继承自UIResponder,所以它们的实例都是responder object对象,都实现了上述4个方法。UIResponder中的默认实现是什么都不做,但UIKit中UIResponder的直接子类(UIView,UIViewController…)的默认实现是将事件沿着responder chain继续向上传递到下一个responder,即nextResponder。所以在定制UIView子类的上述事件处理方法时,如果需要将事件传递给next responder,可以直接调用super的对应事件处理方法,super的对应方法将事件传递给next responder,即使用[super touchesBegan:touches withEvent:event];不建议直接向nextResponder发送消息,这样可能会漏掉父类对这一事件的其他处理。 

[self.nextResponder touchesBegan:touches withEvent:event]; 

另外,在定制UIView子类的事件处理方法时,如果其中一个方法没有调用super的对应方法,则其他方法也需要重写,不使用super的方法,否则事件处理流程会很混乱。

responder chain是一系列连接的responder对象,通过responder对象可以将处理事件的责任传递给下一个,更高级的对象,即当前responder对象的nextResponder。 

iOS中responder chain的结构为:

第一响应者是第一个接收事件的View对象,我们在Xcode的Interface Builder画视图时,可以看到视图结构中就有First Responder。这里的First Responder就是UIApplication了。另外,我们可以控制一个View让其成为First Responder,通过实现 canBecomeFirstResponder方法并返回YES可以使当前View成为第一响应者,或者调用View的becomeFirstResponder方法也可以,例如当UITextField调用该方法时会弹出键盘进行输入,此时输入框控件就是第一响应者。

iOS系统在处理事件时,通过UIApplication对象和每个UIWindow对象的sendEvent:方法将事件分发给具体处理此事件的responder对象(对于触摸事件为hit-test view,其他事件为first responder),当具体处理此事件的responder不处理此事件时,可以通过responder chain交给上一级处理。 

如果hit-test view或first responder不处理此事件,则将事件传递给其nextResponder处理,若有UIViewController对象则传递给UIViewController,传递给其superView。 

如果view的viewController也不处理事件,则viewController将事件传递给其管理view的superView。 

视图层级结构的顶级为UIWindow对象,如果window仍不处理此事件,传递给UIApplication. 

若UIApplication对象不处理此事件,则事件被丢弃。

小结下,使用响应链,能够让一条链上的多个对象对同一事件做出响应。每一个应用有一个响应者链,我们的视图结构是一个N叉树(一个视图可以有多个子视图,一个子视图同一时刻只有一个父视图),而每一个继承自UIResponder的对象都可以在这个N叉树中成为一个节点。当叶节点成为最高响应者的时候,从这个叶节点开始往其父节点开始追溯出一条链,那么对于这一个叶节点来讲,这一条链就是当前的响应者链。响应者链将系统捕获到的UIEvent与UITouch从叶节点层层向上分发,期间可以选择停止分发,也可以继续向上分发。一句话就是事件的传递过程。

10.GCD中栅栏机制

栅栏函数 只能用在调度并发队列中,不能使用在全局并发队列中. 

1.实现高效率的数据库访问和文件访问 

2.避免数据竞争

dispatch_barrier_async函数会等待追加到并行队列上的并行执行的处理全部结束之后,再将制定的处理追加到该并行队列中。然后在由dispatch_barrier_async函数追加的处理执行完毕后,并行队列才恢复为一般的动作,追加到该并行队列的处理又开始执行。

11.Notification响应顺序?

NSNotification使用的是同步操作。即如果你在程序中的A位置post了一个NSNotification,在B位置注册了一个observer,通知发出后,必须等到B位置的通知回调执行完以后才能返回到A处继续往下执行。如果想让NSNotification的post处和observer处异步执行,可以通过NSNotificationQueue实现。

在多线程应用中,Notification在哪个线程中post,就在哪个线程中被转发,而不一定是在注册观察者的那个线程中。 Notification的发送与接收处理都是在同一个线程中。

对于同一个通知,如果注册了多个观察者,则这多个观察者的执行顺序和他们的注册顺序是保持一致的。 

这里讲到了“重定向”,就是我们在Notification所在的默认线程中捕获这些分发的通知,然后将其重定向到指定的线程中。

为了顺应语法的变化,apple 从 ios4 之后提供了带有 block 的 NSNotification。

一种重定向的实现思路是自定义一个通知队列(注意,不是NSNotificationQueue对象,而是一个数组),让这个队列去维护那些我们需要重定向的Notification。我们仍然是像平常一样去注册一个通知的观察者,当Notification来了时,先看看post这个Notification的线程是不是我们所期望的线程,如果不是,则将这个Notification存储到我们的队列中,并发送一个信号(signal)到期望的线程中,来告诉这个线程需要处理一个Notification。指定的线程在收到信号后,将Notification从队列中移除,并进行处理。

当我们注册一个观察者时,通知中心会持有观察者的一个弱引用,来确保观察者是可用的。主线程调用dealloc操作会让Observer对象的引用计数减为0,这时对象会被释放掉。后台线程发送一个通知,如果此时Observer还未被释放,则会用其转出消息,并执行回调方法。而如果在回调执行的过程中对象被释放了,就会出现上面的问题。

12.利用AutoLayout让可变长度标签居中

// ViewController.swift

import UIKit

import SnapKit

class ViewController: UIViewController

{

    override func viewDidLoad() {

        super.viewDidLoad()

        let leftLabel = UILabel()

        leftLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "addText:"))

        leftLabel.userInteractionEnabled = true

        view.addSubview(leftLabel)

        leftLabel.numberOfLines = 0

        leftLabel.text = "All the world's a stage, and all the men and women merely players: they have their exits and their entrances; and one man in his time plays many parts, his acts being seven ages."

        leftLabel.snp_makeConstraints { (make) -> Void in

            make.top.equalTo(40)

            make.left.equalTo(self.view)

            make.right.equalTo(self.view.snp_centerX)

        }

        let rightLabel = UILabel()

        rightLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "addText:"))

        rightLabel.userInteractionEnabled = true

        view.addSubview(rightLabel)

        rightLabel.numberOfLines = 0

        rightLabel.text = "There is a tide in the affairs of men, Which taken at the flood, leads on to fortune. Omitted, all the voyage of their life is bound in shallows and in miseries. On such a full sea are we now afloat. And we must take the current when it serves, or lose our ventures."

        rightLabel.snp_makeConstraints { (make) -> Void in

            make.top.equalTo(40)

            make.right.equalTo(self.view)

            make.left.equalTo(self.view.snp_centerX)

        }

        let bottomView = UIView()

        view.addSubview(bottomView)

        bottomView.backgroundColor = UIColor.redColor()

        bottomView.snp_makeConstraints { (make) -> Void in

            make.height.equalTo(20)

            make.left.right.equalTo(self.view)

            make.top.greaterThanOrEqualTo(leftLabel.snp_bottom)

            make.top.greaterThanOrEqualTo(rightLabel.snp_bottom)

        }

    }

    @objc func addText(recognizer: UIGestureRecognizer) {

        if let label = recognizer.view as? UILabel {

            label.text = label.text! + " I like cheese."

        }

    }

}

让视图的底部和可变高度的Label底部重合。让视图在手机中居中,视图的顶部与可变高度Label保持40个点的高度差。

http://stackoverflow.com/questions/30141870/ios-autolayout-dynamic-uilabel-height

http://www.android100.org/html/201507/06/162126.html

13.Core Data、SQLite是如何使用的?

Core Data是一个功能强大的层,位于SQLite数据库之上,它避免了SQL的复杂性,能让我们以更自然的方式与数据库进行交互。Core Data将数据库行转换为OC对象(托管对象)来实现,这样无需任何SQL知识就能操作他们。 

Core Data能将应用程序中的对象直接保存到数据库中,无需进行复杂的查询,也无需确保对象的属性名和数据库字段名对应,这一切都由Core Data完成。

(CoreData)http://blog.csdn.net/ryantang03/article/details/7794226

(SQLite)http://blog.csdn.net/totogo2010/article/details/7702207

14.归档是如何使用的?

“归档”是指用某种格式来保存一个或多个对象,以便以后还原这些对象的过程。 

只要在类中实现的每个属性都是标量(如int或flloat)或都是符合NSCoding协议的某个类的实例,就可以对你的对象进行完整归档。 

http://blog.csdn.net/backapace/article/details/15812145

15.对Http的理解,socket编程的套路

HTTP协议是基于TCP连接的,是应用层协议,主要解决如何包装数据。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。 

HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务器不能主动给客户端响应(除非采用HTTP长连接技术),iPhone主要使用类NSURLConnection。 

Socket连接:长连接,客户端跟服务器端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务器段保持连接通道,双方可以主动发送数据,一般多用于游戏.Socket默认连接超时时间是30秒,默认大小是8K(理解为一个数据包大小)。

http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html 

http://blog.csdn.net/hguisu/article/details/7444092

16.NSUserDefault使用的时候需要注意什么?

NSUserDefaults非常好用,并不需要用户在程序中设置NSUserDefaults的全局变量,需要在哪里使NSUserDefaults的数据,那么就在哪里创建一个NSUserDefaults对象,然后进行读或者写操作。

针对同一个关键字对应的对象或者数据,可以对它进行重写,重写之后关键字就对应新的对象或者数据,旧的对象或者数据会被自动清理。

注意一点:只能存储基本对象,如果是自定义的对象,需要转换成nsdata存储进去才可以 

iPhone中在本地存储数据简单的说有三种方式:数据库、NSUserDefaults和文件。

NSUserDefaults用于存储数据量小的数据,例如用户配置。并不是所有的东西都能往里放的,只支持:NSString, NSNumber, NSDate, NSArray, NSDictionary,

如果把一个自定义的类存到一个NSArray里,然后再存到NSUserDefaults里也是不能成功的。

17.ARC的底层实现机制

18.滑动TableView视图的时候NSTimer会不会工作?

1.默认情况下NSTimer不能在后台正常工作: 

2.滑动UI时NSTimer不能工作:

这其实就是runloop的mode在做怪。 

runloop可以理解为cocoa下的一种消息循环机制,用来处理各种消息事件,我们在开发 的时候并不需要手动去创建一个runloop,因为框架为我们创建了一个默认的runloop,通过[NSRunloop currentRunloop]我们可以得到一个当前线程下面对应的runloop对象,不过我们需要注意的是不同的runloop之间消息的通知方式。

接着上面的话题,在开启一个NSTimer实质上是在当前的runloop中注册了一个新的事件源,而当scrollView滚动的时候,当前的 MainRunLoop是处于UITrackingRunLoopMode的模式下,在这个模式下,是不会处理NSDefaultRunLoopMode 的消息(因为RunLoop Mode不一样),要想在scrollView滚动的同时也接受其它runloop的消息,我们需要改变两者之间的runloopmode.

1 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 

简单的说就是NSTimer不会开启新的进程,只是在Runloop里注册了一下,Runloop每次loop时都会检测这个timer,看是否可 以触发。当Runloop在A mode,而timer注册在B mode时就无法去检测这个timer,所以需要把NSTimer也注册到A mode,这样就可以被检测到。

19.绘制图形

- (void)drawRect:(CGRect)rect

{

    // Drawing code

    // 1.获得图形上下文

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // 2.拼接图形(路径)

    // 设置线段宽度

    CGContextSetLineWidth(ctx, 10);

    // 设置线段头尾部的样式

    CGContextSetLineCap(ctx, kCGLineCapRound);

    // 设置线段转折点的样式

    CGContextSetLineJoin(ctx, kCGLineJoinRound);

    /**  第1根线段  **/

    // 设置颜色

    CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);

    // 设置一个起点

    CGContextMoveToPoint(ctx, 10, 10);

    // 添加一条线段到(100, 100)

    CGContextAddLineToPoint(ctx, 100, 100);

    // 渲染一次

    CGContextStrokePath(ctx);

    /**  第2根线段  **/

    // 设置颜色

    CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);

    // 设置一个起点

    CGContextMoveToPoint(ctx, 200, 190);

    // 添加一条线段到(150, 40)

    CGContextAddLineToPoint(ctx, 150, 40);

    CGContextAddLineToPoint(ctx, 120, 60);

    // 3.渲染显示到view上面

    CGContextStrokePath(ctx);

}

20.构建缓存时选用NSCache而非NSDictionary

当系统资源将要耗尽时,NSCache可以自动删减缓存。如果采用普通的字典,那么就要自己编写挂钩,在系统发出"低内存"通知时手工删减缓存,NSCache会先行删减"最久未使用的"对象。

NSCache并不会"拷贝"键,而是会"保留"它。此行为用NSDictionary也可以实现,但是需要编写比较复杂的代码。NSCache对象不拷贝键的原因在于:很多时候,键都是由不支持拷贝操作的对象来充当的。因此,NSCache对象不会自动拷贝键,所以说,在键不支持拷贝操作的情况下,该类用起来比字典更方便。

NSCache是线程安全的,NSDictionary不是。在开发者自己不编写加锁代码的前提下,多个线程便可以同时访问NSCache。对缓存来说,线程安全通常很重要,因为开发者可能要在某个线程中读取数据,此时如果发现缓存里找不到指定的键,那么就要下载该键所对应的数据了。

如果缓存使用得当,那么应用程序的响应速度就能提高。只有那种"重新计算起来很费事的"数据,才值得放入缓存,比如那些需要从网络获取或从磁盘读取的数据。

21.介绍项目。项目用了什么第三方框架?AFNetWorking用的什么版本?它是基于什么的?有没有读过第三方框架源码?

SVProgressHub 

AFNetWorking 

SDWebImage

AFNetWorking 2.0 

AFNetWorking是基于NSURLConnection和NSURLSession的基础上进行封装的,逻辑简单清楚,设计思路很好。AFNetWorking利用的是异步加载数据的方式,而且是代理的方式。

http://www.jianshu.com/p/358dc280fb33

22.谈谈Runtime

today 

运行期组件

23.谈谈Runloop,Runloop是怎样持续监听事件从而实现线程保活?如果线程启用Runloop,它会一直占用CPU吗?

http://www.jianshu.com/p/10121d699c32

Run Loop是一让线程能随时处理事件但不退出的机制。RunLoop 实际上是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。

OSX/iOS 系统中,提供了两个这样的对象:NSRunLoop 和 CFRunLoopRef。CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。NSRunLoop 是基于 CFRunLoopRef 的封装,提供了面向对象的 API,但是这些 API 不是线程安全的。 

线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。你只能在一个线程的内部获取其 RunLoop(主线程除外)。

Run Loop的四个作用: 

(1)使程序一直运行接受用户输入 

(2)决定程序在何时应该处理哪些Event 

(3)调用解耦 

(4)节省CPU时间

主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main() 函数:

http://blog.csdn.net/potato512/article/details/51455728

28.说说对临界区的理解。临界资源有什么特点?为什么会发生死锁?死锁怎么预防?发生了死锁怎么办?

today 

http://www.cnblogs.com/Jessy/p/3540724.html

29.上线APP的crash收集

1.找到开发者账号进入iTunes connect 

2.进入app分析,查看app查看情况,app下载量,app崩溃情况 

3.去查看app的崩溃的分布版本和手机系统版本 

4.打开xcode下载崩溃日志,product-Archive-crashes 查看响应版本的崩溃日志。 

5.点击对应的崩溃日志,后面会出现一个箭头,点击箭头就会进入到xcode中对应的代码行

30.动画掉帧,CADisPlayLink, Core graphics

尝试使用KMCGeigerCounter检测动画掉帧问题(指示器)

CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器。我们在应用中创建一个新的 CADisplayLink 对象,把它添加到一个runloop中,并给它提供一个 target 和selector 在屏幕刷新的时候调用。另外CADisplayLink 不能被继承。 

frameInterval属性是可读可写的NSInteger型值,标识间隔多少帧调用一次selector 方法,默认值是1,即每帧都调用一次。如果每帧都调用一次的话,对于iOS设备来说那刷新频率就是60HZ也就是每秒60次,如果将 frameInterval 设为2 那么就会两帧调用一次,也就是变成了每秒刷新30次。 

我们通过pause属性开控制CADisplayLink的运行。当我们想结束一个CADisplayLink的时候,应该调用-(void)invalidate 

从runloop中删除并删除之前绑定的 target跟selector 

另外CADisplayLink 不能被继承。

iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确度相当高。 

NSTimer的精确度就显得低了点,比如NSTimer的触发时间到的时候,runloop如果在阻塞状态,触发时间就会推迟到下一个runloop周期。并且 NSTimer新增了tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。 

CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引擎或者视频播放的渲染。NSTimer的使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用。在UI相关的动画或者显示内容使用 CADisplayLink比起用NSTimer的好处就是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。

注意 

通常来讲:iOS设备的刷新频率事60HZ也就是每秒60次。那么每一次刷新的时间就是1/60秒 大概16.7毫秒。当我们的frameInterval值为1的时候我们需要保证的是 CADisplayLink调用的`target`的函数计算时间不应该大于 16.7否则就会出现严重的丢帧现象。 

在mac应用中我们使用的不是CADisplayLink而是 CVDisplayLink它是基于C接口的用起来配置有些麻烦但是用起来还是很简单的。

使用ARC是否会出现野指针,为什么?

定义block的时候,是将block内存分配在堆上的。当在函数作用范围外的 时候block的内存会被回收释放,就会生成野指针,这时候去调用block,就crash.

如何让对异步方法进行二次封装让其同步执行

可以用dispatch_group_async, dispatch_group_notify

为什么这么去定义单例?

为什么使用GCD去创建单例,GCD中的dispatch_once函数只调用一次,多线程中若有两个线程先后去执行到dispatch_once这个地方,则先执行到的会去调用,后执行的就不会调用了。

为什么要让对象指针static, 多线程情况下,因为dispatch_once只执行一次,除了第一个执行的,之后的线程都不执行,直接返回对象指针,若此时指针是临时变量,则会导致返回一个空指针,若为static则返回的永远是同一个又第一个执行的生成的对象。

PNG和JPEG的区别

PNG格式可以保存为透明背景的图片,JPEG不可以。

PNG格式图片具有高保真性、透明性、文件体积小等特性。

JPEG有损压缩。

31.如何给按钮画边框

32.Socket和Http的区别,和TCP的区别。

Socket套接字

套接字(socket)是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协 议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以 和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。 

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

4、SOCKET连接与TCP连接 

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。 

若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以 保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP 文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”

形象的理解: 

把IP想像成一种高速公路,IP负责在通信双方地点间规划线路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,TCP负责车辆管理,发出多少车辆,车辆丢失后重新发车,路途中车辆太多减少发车量之类的,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议,HTTP负责把数据信息包装起来,Socket就像两个通信双方的地点,创建Socket就像打开通信端口,打开车库的大门。

HTTP请求报文:一个HTTP请求报文由请求行、请求头部、空行和请求数据4部分组成。 

HTTP响应报文:由三部分组成:状态行、消息报头、响应正文。

1、HTTP协议的几个重要概念 

1.连接(Connection):一个传输层的实际环流,它是建立在两个相互通讯的应用程序之间。 

2.消息(Message):HTTP通讯的基本单位,包括一个结构化的八元组序列并通过连接传输。 

3.请求(Request):一个从客户端到服务器的请求信息包括应用于资源的方法、资源的标识符和协议的版本号 

4.响应(Response):一个从服务器返回的信息包括HTTP协议的版本号、请求的状态(例如“成功”或“没找到”)和文档的MIME类型。 

5.资源(Resource):由URI标识的网络数据对象或服务。 

6.实体(Entity):数据资源或来自服务资源的回映的一种特殊表示方法,它可能被包围在一个请求或响应信息中。一个实体包括实体头信息和实体的本身内容。 

7.客户机(Client):一个为发送请求目的而建立连接的应用程序。 

8.用户代理(Useragent):初始化一个请求的客户机。它们是浏览器、编辑器或其它用户工具。 

9.服务器(Server):一个接受连接并对请求返回信息的应用程序。 

10.源服务器(Originserver):是一个给定资源可以在其上驻留或被创建的服务器。 

11.代理(Proxy):一个中间程序,它可以充当一个服务器,也可以充当一个客户机,为其它客户机建立请求。请求是通过可能的翻译在内部或经过传递到其它的服务器中。一个代理在发送请求信息之前,必须解释并且如果可能重写它。 

代理经常作为通过防火墙的客户机端的门户,代理还可以作为一个帮助应用来通过协议处理没有被用户代理完成的请求。 

12.网关(Gateway):一个作为其它服务器中间媒介的服务器。与代理不同的是,网关接受请求就好象对被请求的资源来说它就是源服务器;发出请求的客户机并没有意识到它在同网关打交道。 

网关经常作为通过防火墙的服务器端的门户,网关还可以作为一个协议翻译器以便存取那些存储在非HTTP系统中的资源。 

13.通道(Tunnel):是作为两个连接中继的中介程序。一旦激活,通道便被认为不属于HTTP通讯,尽管通道可能是被一个HTTP请求初始化的。当被中继的连接两端关闭时,通道便消失。当一个门户(Portal)必须存在或中介(Intermediary)不能解释中继的通讯时通道被经常使用。 

14.缓存(Cache):反应信息的局域存储。

客户端可以通过客户机或者用户代理与服务器相互发送消息的形式建立连接(客户端请求报文,服务器响应报文),请求报文里包含请求的资源定位符,请求的方法,响应报文里包含资源的实体,当服务器返回响应报文后连接断开。这是一个简单HTTP连接的过程。

HTTP

http://www.cnblogs.com/renyuan/archive/2013/01/19/2867720.html

33. OC对象模型

对象是OC中基本构造单元 (building block),用于存储和传递数据。类和对象的最终实现都是一种数据结构 

一个完整的类应该包括类方法、实例方法和成员变量(实例变量), 每个对象都包括一个isa(is a class)指针指向类对象(运行时方法发送给对象消息,才确定类别并调用相应的方法实现),类对象结构中记载了类的所有信息。 

类对象的isa指向元类对象(meta class),类对象中的方法列表是实例方法(-, instance methods), 元类对象中的方法列表是类方法(+, class methods)

34.HTTPS和HTTP的区别

1、HTTPS是加密传输协议,HTTP是明文传输协议; 

2、HTTPS需要用到SSL证书,而HTTP不用; 

3、HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO; 

4、HTTPS标准端口443,HTTP标准端口80; 

5、HTTPS基于传输层,HTTP基于应用层; 

6、HTTPS在浏览器显示绿色安全锁,HTTP没有显示;

http://blog.devtang.com/2013/10/15/objective-c-object-model/

35.使用atomic一定是线程安全的吗?

1.具备atomic特质的获取方法会通过锁定机制来确保其操作的原子性。 

2.不加锁的话,一个线程正在改写某属性值的时候,另外一个线程也许会突然闯入,把尚未修改好的属性值读取出来。 

3.声明为atomic,但如果一个线程在连续多次读取某个属性值的过程中有别的线程在同时改写该值,也还是会读取到不同的属性值。

A线程结束完写操作后,B线程进行写操作,之后A线程进行读操作的时候读取的是B线程的值,破坏了线程安全。

4.atomic需要同步锁,开销大。

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

36.__block在arc和非arc下含义一样吗?

一般在block中修改变量都需要事先加block进行修饰。 

在非arc中,block修饰的变量的引用计算是不变的。 

在arc中,会引用到,并且计算+1;

37.什么是method swizzling?

38.如何高性能的给UIImageView加个圆角?

我觉得应该是使用Quartz2D直接绘制图片,得把这个看看。 

步骤: 

a、创建目标大小(cropWidth,cropHeight)的画布。

  b、使用UIImage的drawInRect方法进行绘制的时候,指定rect为(-x,-y,width,height)。

c、从画布中得到裁剪后的图像。 


``` 

- (UIImage*)cropImageWithRect:(CGRect)cropRect 

CGRect drawRect = CGRectMake(-cropRect.origin.x , -cropRect.origin.y, self.size.width * self.scale, self.size.height * self.scale);

UIGraphicsBeginImageContext(cropRect.size);

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextClearRect(context, CGRectMake(0, 0, cropRect.size.width, cropRect.size.height));

[self drawInRect:drawRect];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;

}

``` 


39.UIView和CALayer是什么关系?

UIView 是 CALayer 的CALayerDelegate 

1.首先UIView可以响应事件,Layer不可以. 

UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。

2.View和CALayer的Frame映射及View如何创建CALayer. 

一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的 frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性。

3.UIView主要是对显示内容的管理而 CALayer 主要侧重显示内容的绘制。 

4.在做 iOS 动画的时候,修改非 RootLayer的属性(譬如位置、背景色等)会默认产生隐式动画,而修改UIView则不会。

40.使用drawRect有什么影响?

rawRect会利用CPU生成offscreen bitmap,从而减轻GPU的绘制压力,用这种方式最UI可以将动画流畅性优化到极致,但缺点是绘制api复杂,offscreen cache增加内存开销。UI动画流畅性的优化主要平衡CPU和GPU的工作压力。

drawRect方法依赖Core Graphics框架来进行自定义的绘制,但这种方法主要的缺点就是它处理touch事件的方式:每次按钮被点击后,都会用setNeddsDisplay进行强制重绘;而且不止一次,每次单点事件触发两次执行。这样的话从性能的角度来说,对CPU和内存来说都是欠佳的。特别是如果在我们的界面上有多个这样的UIButton实例。

41.设计简单的图片内存缓存器(移除策略要说)

常见的有FIFO,LRU,LRU-2,2Q等等。由于NSCache的缓存策略不透明,一些app开发者会选择自己做一套cache机制,其实并不难。

42.用过coreData或者sqlite吗?读写是分线程的吗?遇到过死锁没?如何解决

43.二叉搜索树?search的时间复杂度是多少?

44.loadView是干嘛用的?

当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewController就会自动调用loadView这个方法。这个方法就会加载或者创建一个view对象,赋值给view属性。 

loadView默认做的事情是:如果此ViewController存在一个对应的nib文件,那么就加载这个nib。否则,就创建一个UIView对象。

如果你用Interface Builder来创建界面,那么不应该重载这个方法。

如果你想自己创建view对象,那么可以重载这个方法。此时你需要自己给view属性赋值。你自定义的方法不应该调用super。如果你需要对view做一些其他的定制操作,在viewDidLoad里面去做。

如果你想自己控制view对象的创建,例如创建一个特殊尺寸的view,那么可以重载这个方法,自己创建一个UIView对象,然后指定 self.view = myView; 但这种情况也没有必要调用super,因为反正你也不需要在super方法里面创建的view对象。

45.viewWillLayoutSubView是?

layoutSubviews在以下情况下会被调用:

1、init初始化不会触发layoutSubviews

但是是用initWithFrame 进行初始化时,当rect的值不为CGRectZero时,也会触发

2、addSubview会触发layoutSubviews

3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化

4、滚动一个UIScrollView会触发layoutSubviews

5、旋转Screen会触发父UIView上的layoutSubviews事件

6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

46.如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter?

遵循NSCopying协议并实现方法copyWithZone就可以让自己的类用copy修饰符

- (void)setName:(NSString *)name {

    _name = [name copy];

}

如果是只读属性,可以在初始化init函数里完成name copy操作

47.@protocol 和 category 中如何使用 @property

建立关联引用。 

http://www.jianshu.com/p/3cbab68fb856

48.runtime 如何实现 weak 属性

weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 

那么runtime如何实现weak变量的自动置nil? 

runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。

49.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

包含特性的成员变量。 

@property = ivar + getter + setter

Ivar可以理解为类中的一个变量,主要作用是用来保存数据的。

“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。

完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做"自动合成"。这个过程是由编译器在编译期执行,除了生成方法代码getter、setter之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。

49.1@synthesize和@dynamic分别有什么作用?

1)@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var; 

2)@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。 

3)@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

50.ARC下,不显式指定任何属性关键字时,默认的关键字都有哪些?

对应基本数据类型默认关键字是 

atomic,readwrite,assign 

对于普通的OC对象 

atomic,readwrite,strong

51.@synthesize合成实例变量的规则是什么?假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么?

实例变量 = 成员变量 = ivar 

总结下@synthesize合成实例变量的规则,有以下几点: 

1)如果指定了成员变量的名称,会生成一个指定的名称的成员变量, 

2)如果这个成员已经存在了就不再生成了. 

3)如果是 @synthesize foo; 还会生成一个名称为foo的成员变量,也就是说:如果没有指定成员变量的名称会自动生成一个属性同名的成员变量。 

4)如果是 @synthesize foo = _foo; 就不会生成成员变量了.

假如property名为foo,存在一个名为_foo的实例变量,那么还会自动合成新变量么? 不会。

52.在有了自动合成属性实例变量之后,@synthesize还有哪些使用场景?

53.什么时候会报unrecognized selector的异常?

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果,在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。但是在这之前,objc的运行时会给出三次拯救程序崩溃的机会:

53.1objc中向一个nil对象发送消息将会发生什么?

在Objective-C中向nil发送消息是完全有效的——只是在运行时不会有任何作用: 

如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)。例如: 

Person * motherInlaw = [[aPerson spouse] mother]; 

如果spouse对象为nil,那么发送给nil的消息mother也将返回nil。

1)如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者long long的整型标量,发送给nil的消息将返回0。 

2)如果方法返回值为结构体,发送给nil的消息将返回0。结构体中各个字段的值将都是0。 

3)如果方法的返回值不是上述提到的几种情况,那么发送给nil的消息的返回值将是未定义的。 

objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。

objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。 那么,回到本题,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

54.一个objc对象的isa的指针指向什么?有什么作用?

指向他的类对象,从而可以找到对象上的方法

每个Objective-C对象都有一个隐藏的数据结构,这个数据结构是Objective-C对象的第一个成员变量,它就是isa指针。这个指针指向哪呢?它指向一个类对象(class object 记住它是个对象,是占用内存空间的一个变量,这个对象在编译的时候编译器就生成了,专门来描述某个类的定义),这个类对象包含了Objective-C对象的一些信息(为了区分两个对象,我把前面提到的对象叫Objective-C对象),包括Objective-C对象的方法调度表,实现了什么协议等等。这个包含信息就是Objective-C动态能力的根源了

代码输出

@implementation Son : Father

- (id)init

{

    self = [super init];

    if (self) {

        NSLog(@"%@", NSStringFromClass([self class]));

        NSLog(@"%@", NSStringFromClass([super class]));

    }

    return self;

}

@end

代码输出都是son, 因为self class和super class都是以这个son实例为参数,去调用自己的class方法或father的class方法,结果他们都没实现,都调用的是NSObject的class方法,参数是同一个son,故结果都输出son

两个很大整数做乘法

分治法。 

两个大整数用字符串保存,输出结果用字符串保存。 

采用乘法的交叉相乘原理。

什么时候用HTTP, 什么时候用TCP

HTTP:超文本传输协议。当需要传输一些超文本的时候,用HTTP 

HTTP是制定出来的,方便传输一些超文本的协议。

TCP:控制传输方式的协议。保证数据传输可靠性的一个方式。可在其基础上定制协议以实现多种文件的传输。

在block之外有一个NSMutableArray, 不采用__block修饰符可以改变其值么。

可以。为什么呢,因为我们只是对截获的变量进行了操作,而没有进行赋值,所以对于截获变量,可以进行操作而不可以进行赋值。 

我们引用的是指针,当只是操作并不会改变指针的指向,赋值的话就会引发指针指向的改变。block禁止的是指针指向的改变

使用get_current_queue会导致死锁么?为什么?

55.一个objc对象如何进行内存布局?(考虑有父类的情况)

所有父类的成员变量和自己的成员变量都会存放在该对象所对应的存储空间中. 

每一个对象内部都有一个isa指针,指向他的类对象,类对象中存放着本对象的 

1)对象方法列表(对象能够接收的消息列表,保存在它所对应的类对象中) 

2)成员变量的列表 

3)属性列表 

它内部也有一个isa指针指向元对象(meta class),元对象内部存放的是类方法列表,类对象内部还有一个superclass的指针,指向他的父类对象。


1)根对象就是NSobject,它的superclass指针指向nil。 

2)类对象既然称为对象,那它也是一个实例。类对象中也有一个isa指针指向它的元类(meta class),即类对象是元类的实例。元类内部存放的是类方法列表,根元类的isa指针指向自己,superclass指针指向NSObject类。 

56.使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

在ARC下不需要 

在MRC中,对于使用retain或copy策略的需要

57.objc中的类方法和实例方法有什么本质区别和联系?

类方法: 

类方法是属于类对象的 

类方法只能通过类对象调用 

类方法中的self是类对象 

类方法可以调用其他的类方法 

类方法中不能访问成员变量 

类方法中不能直接调用对象方法

实例方法: 

实例方法是属于实例对象的 

实例方法只能通过实例对象调用 

实例方法中的self是实例对象 

实例方法中可以访问成员变量 

实例方法中直接调用实例方法 

实例方法中也可以调用类方法(通过类名)

58._objc_msgForward函数是做什么的,直接调用它将会发生什么?

_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。

直接调用_objc_msgForward是非常危险的事,如果用不好会直接导致程序Crash,但是如果用得好,能做很多非常酷的事。

一旦调用_objc_msgForward,将跳过查找 IMP 的过程,直接触发“消息转发”,如果调用了_objc_msgForward,即使这个对象确实已经实现了这个方法,你也会告诉objc_msgSend:“我没有在这个对象里找到这个方法的实现”

59.runloop的mode作用是什么?

model 主要是用来指定事件在运行循环中的优先级的,分为:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态 

UITrackingRunLoopMode:ScrollView滑动时 

UIInitializationRunLoopMode:启动时 

NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

苹果公开提供的 Mode 有两个: 

NSDefaultRunLoopMode(kCFRunLoopDefaultMode) 

NSRunLoopCommonModes(kCFRunLoopCommonModes)

60.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

不能向编译后得到的类中增加实例变量; 

能向运行时创建的类中添加实例变量; 

解释下:

因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;

运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。

61.runloop和线程有什么关系?runloop和线程有什么关系?

62.以+ scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

RunLoop只能运行在一种mode下,如果要换mode,当前的loop也需要停下重启成新的。利用这个机制,ScrollView滚动过程中NSDefaultRunLoopMode(kCFRunLoopDefaultMode)的mode会切换到UITrackingRunLoopMode来保证ScrollView的流畅滑动:只能在NSDefaultRunLoopMode模式下处理的事件会影响ScrollView的滑动。

如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。

同时因为mode还是可定制的,所以:

Timer计时会被scrollView的滑动影响的问题可以通过将timer添加到NSRunLoopCommonModes(kCFRunLoopCommonModes)来解决。 

这个模式等效于NSDefaultRunLoopMode和NSEventTrackingRunLoopMode的结合。两个模式以数组的形式组合成一个形式,当只要其中任意一个模式触发,都是这个大模式的触发。都可响应。 

http://www.aichengxu.com/view/6772291

63.猜想runloop内部是如何实现的?

while起到跳出条件检测,若不满足则一直不跳出。 

在while里有一个一直监听唤醒时间的东西,监听到就立马处理。之后又循环回来监听,知道满足跳出条件

function loop() {

    initialize();

    do {

        var message = get_next_message();

        process_message(message);

    } while (message != quit);

}

objc使用什么机制管理对象内存?

通过 retainCount 的机制来决定对象是否需要释放。 每次 runloop 的时候,都会检查对象的 retainCount,如果retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了。

64.BAD_ACCESS在什么情况下出现?

访问了野指针,比如对一个已经释放的对象执行了release、访问已经释放对象的成员变量或者发消息。 死循环

65.苹果是如何实现autoreleasepool的?

autoreleasepool 以一个队列数组的形式实现,主要通过下列三个函数完成.

objc_autoreleasepoolPush 

objc_autoreleasepoolPop 

objc_autorelease 

看函数名就可以知道,对 autorelease 分别执行 push,和 pop 操作。销毁对象时执行release操作。

举例说明:我们都知道用类方法创建的对象都是 Autorelease 的,那么一旦 Person 出了作用域,当在 Person 的 dealloc 方法中打上断点,我们就可以看到这样的调用堆栈信息

66.使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?

系统的某些block api中,UIView的block版本写动画时不需要考虑,但也有一些api 需要考虑:

所谓“引用循环”是指双向的强引用,所以那些“单向的强引用”(block 强引用 self )没有问题,比如这些:

[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }]; 

[[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }]; 

[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification" 

object:nil 

queue:[NSOperationQueue mainQueue] 

usingBlock:^(NSNotification * notification) { 

self.someProperty = xyz; }]; 

这些情况不需要考虑“引用循环”。

但如果你使用一些参数中可能含有 ivar 的系统 api ,如 GCD 、NSNotificationCenter就要小心一点:比如GCD 内部如果引用了 self,而且 GCD 的其他参数是 ivar,则要考虑到循环引用:

weak __typeof(self) weakSelf = self; 

dispatch_group_async(_operationsGroup, _operationsQueue, ^ 

typeof(self) strongSelf = weakSelf; 

[strongSelf doSomething]; 

[strongSelf doSomethingElse]; 

} ); 

类似的:

weak __typeof(self) weakSelf = self; 

_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey" 

object:nil 

queue:nil 

usingBlock:^(NSNotification *note) { 

typeof(self) strongSelf = weakSelf; 

[strongSelf dismissModalViewControllerAnimated:YES]; 

}]; 

self --> _observer --> block --> self 显然这也是一个循环引用。

67.苹果为什么要废弃dispatch_get_current_queue?

dispatch_get_current_queue容易造成死锁

68.如何手动触发一个value的KVO

复习大全里有

69.若一个类有实例变量NSString *_foo,调用setValue:forKey:时,可以以foo还是_foo作为key?

都可以。

70.KVC和KVO的keyPath一定是属性么?KVC的keyPath中的集合运算符如何使用?

KVO支持实例变量

必须用在集合对象上或普通对象的集合属性上 

简单集合运算符有@avg, @count , @max , @min ,@sum. age为键 

格式 @"@sum.age"或 @"集合属性.@max.age"

71.如何关闭默认的KVO的默认实现,并进入自定义的KVO实现?

http://tech.glowing.com/cn/implement-kvo/

73.IB中User Defined Runtime Attributes如何使用?

它能够通过KVC的方式配置一些你在interface builder 中不能配置的属性。当你希望在IB中作尽可能多得事情,这个特性能够帮助你编写更加轻量级的viewcontroller 

比如设置边界的宽度,添加name属性。

74.如何调试BAD_ACCESS错误

1.通过僵尸对象 

2.设置全局断点快速定位问题代码所在行 

3.Xcode 7 已经集成了BAD_ACCESS捕获功能:Address Sanitizer。 用法如下:在配置中勾选:white_check_mark:Enable Address Sanitizer

代理属性设置为assign会导致crash崩溃,报错EXC_BAD_ACCESS 经由一番研讨,发明若是应用 @property (nonatomic, assign, readwrite) id delegate; 声明一个delegate之前一直使用的是assign,今天调试一段代码的时候,发现程序会crash掉,报错EXC_BAD_ACCESS

经过一番研究,发现如果使用 

@property (nonatomic, assign, readwrite) id delegate; 

声明一个delegate,那么即便delegate指向的对象销毁了,delegate中依然会保存之前对象的地址 

即,delegate成为了一个野指针... 

而使用weak,则不会有上述问题,当delegate指向的对象销毁后,delegate = nil, 

所以答案就是,使用weak。

75.lldb(gdb)常用的调试命令?

(命令)和(子命令):LLDB调试命令的名称。命令和子命令按层级结构来排列:一个命令对象为跟随其的子命令对象创建一个上下文,子命令又为其子命令创建一个上下文,依此类推。 2. :执行命令的操作 3. :命令选项 4. :命令的参数 5. []:表示命令是可选的,可以有也可以没有.

打印对象po

如果我们想打印对象。我们需要使用命令选项:-O。为了更方便的使用,LLDB为expression -O –定义了一个别名:po 

执行表达式expression

执行某个表达式。 我们在代码运行过程中,可以通过执行某个表达式来动态改变程序运行的轨迹。 假如我们在运行过程中,突然想把self.view颜色改成红色,看看效果。我们不必写下代码,重新run,只需暂停程序,用expression改变颜色,再刷新一下界面,就能看到效果

改变颜色 

刷新界面 

将返回值输出 

设置断点

breakPoint set 表示设置断点,-n表示根据方法名name设置断点,main为方法名参数。

使用-f指定文件 

我们只需要给ViewController.m文件中的viewDidLoad设置断点: 

这里需要注意,如果方法未写在文件中(比如写在category文件中,或者父类文件中),指定文件之后,将无法给这个方法设置断点。

使用-l指定文件某一行设置断点 

我们想给ViewController.m第38行设置断点 

使用-c设置条件断点 

text:方法接受一个ret的参数,我们想让ret == YES的时候程序中断: 

有的时候我们可能暂时不想要某个断点,可以使用breakpoint disable让某个断点暂时失效 e.g: 我们来让刚刚的断点4失效 

enable使断点重新生效

breakpoin查看设置了哪些断点

76.你知道ios里面存数据有哪些方法吗?

我答曰:归档,NSUserDefault,Core Data,sqlite,plist,app sandbox里面的文件夹,如应用沙盒一般包括以下几个文件目录:应用程序包、Documents、Libaray(下面有Caches和Preferences目录)、tmp。 

Documents:保存应用运行时生成的需要持久化的数据,iTunes会自动备份该目录。苹果建议将程序中建立的或在程序中浏览到的文件数据保存在该目录下,iTunes备份和恢复的时候会包括此目录。 

tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也有可能会清除该目录下的文件,iTunes不会同步该目录。iphone重启时,该目录下的文件会丢失。 

Library:存储程序的默认设置和其他状态信息,iTunes会自动备份该目录。 

Libaray/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除。一般存放体积比较大,不是特别重要的资源。 

Libaray/Preferences:保存应用的所有偏好设置,ios的Settings(设置)应用会在该目录中查找应用的设置信息,iTunes会自动备份该目录。

//第一种方式

[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];其他的都一样 

//第二种方式

// 获得应用程序沙盒的Documents文件夹路径

NSArray *arrDocumentPaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);

// 获得应用程序沙盒的Caches文件夹路径

NSArray *arrCachesPaths=NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES);

// 获得应用程序沙盒的Downloads文件夹路径

NSArray *arrDownloadPaths=NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory,NSUserDomainMask,YES);

// 获得应用程序沙盒的home文件夹路径

NSString *homePath= NSHomeDirectory();

// 获得应用程序沙盒的tmp文件夹路径

NSString *TmpPath= NSTemporaryDirectory();

78.NSUrlsession 和 NSUrlconnection的区别

NSURLSession是NSURLConnection 的替代者,是对NSURLConnection进行了重构优化后的新的网络访问接口。

与NSURLConnection相比,NSURLSession最直接的改善就是提供了配置每个会话的缓存,协议,cookie和证书政策(credential policies),甚至跨应用程序共享它们的能力。这使得框架的网络基础架构和部分应用程序独立工作,而不会互相干扰。

NSURLSession相对于NSConnection来说,比较具体的优势。 

1、后台上传和下载 

2、可以暂停和重启网络操作 

3、可以对缓存策略,session类型、任+ 

务类型(比如上传、下载等任务)进行单独的配置 

4、更多更丰富的代理模式

NSURLSession也是指一组相互依赖的类。NSURLSession包括与之前相同的组件,例如NSURLRequest, NSURLCache等。NSURLSession的不同之处在于,它把 NSURLConnection替换为NSURLSession, NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask。

79.frame bounds center 的区别。会让你在纸上画出来各自的变化

frame是相对于其它视图 

bounds是相对于本身,本地坐标系。管理的是子视图添加进本视图的一个过程。设置bounds为(-20,-20,...,...)如果子视图的frame是(0, 0, ..., ...),那么就会以距左边界20,距上边界20这样的形式添加进来。因为子视图的frame坐标是以母视图的bounds坐标为准。 

center.x = frame.origin.x + frame.width / 2 

center.y = frame.origin.y + frame.height / 2

80.线程共享进程资源的实例,在iOS中。

NSUserDefault?

81.OC运行时能加实例变量吗

可以。 

运行时可动态添加方法,在此方法里去初始化实例变量。

82.64位下nsnumber的优化。

83.ipa包、编译相关

83.1NSThread NSOperation dispatch 和 gcd的关系

NSThread:–优点:NSThread 比其他两个轻量级,使用简单 

缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销

NSOperation:–不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上–NSOperation是面向对象的,属于OC类

GCD:–Grand CentralDispatch是由苹果开发的一个多核编程的解决方案。是相比NSThread, NSOperation更高效和强大的技术–GCD是基于C的底层API。 

GCD主要是建立个个线程时间的依赖关系这类的情况,更高的并发执行能力。

84.iOS常用回调方式等

delegate回调,kvo回调,NSNotification回调,block回调

85.声明delegate的时候为什么用assign,而不用weak等等。

weak比assgin线程更安全。

但在delegate成员变量这个细分领域,我们即可以用weak,又可以用assign。因为在几乎所有场景下,delegate所指向的对象C的生存期都是覆盖了delegate成员变量本身所在的对象D的生存期的,所以,在D的生存期内,C所使用的D的指针都是有效的,所以这个时候使用assign是没有关系的。

86.用过Block没有

网络响应block回调。对响应数据进行一个包装作为参数调用控制器的函数。

87.信号机制什么的,还有二叉树的深度优先和广度优先遍历算法。

88.有一个a[1000]的数组,存放1-1000的数,现在有一个数重复了,用一个时间复杂度为N的算法找到重复的数值

89.猴子摘香蕉,共50个,一次可以摘一个或两个,问摘法种数

90.iOS crash后的调试方法?

线上收集,Xcode中下载崩溃日志。

91.OC中深拷贝,浅拷贝

对不可变对象,copy则执行浅拷贝,mutablCopy则执行深拷贝。对可变对象,copy和mutableCopy都执行深拷贝,但是copy返回的对象是不可变的。

92.Appdelegate几个回调?vc几个回调的时机?写个itoa

AppDelegate回调时机

各个程序运行状态时代理的回调: 

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

告诉代理进程启动但还没进入状态保存 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

告诉代理启动基本完成程序准备开始运行 

- (void)applicationWillResignActive:(UIApplication *)application 

当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或事件,比如来电话了 

- (void)applicationDidBecomeActive:(UIApplication *)application 

当应用程序入活动状态执行,这个刚好跟上面那个方法相反 

- (void)applicationDidEnterBackground:(UIApplication *)application 

当程序被推送到后台的时候调用。所以要设置后台继续运行,则在这个函数里面设置即可 

- (void)applicationWillEnterForeground:(UIApplication *)application 

当程序从后台将要重新回到前台时候调用,这个刚好跟上面的那个方法相反。 

- (void)applicationWillTerminate:(UIApplication )application 

当程序将要退出是被调用,通常是用来保存数据和一些退出前的清理工作。这个需要要设置UIApplicationExitsOnSuspend的键值。 

- (void)applicationDidFinishLaunching:(UIApplication

)application 

当程序载入后执行

itoa 将数值转换成相应进制的字符串

94.iOS沙盒机制

iOS应用程序只能在为该改程序创建的文件系统中读取文件,不可以去其它地方访问,此区域被成为沙盒,所以所有的非代码文件都要保存在此,例如图像,图标,声音,映像,属性列表,文本文件等。 

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

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

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

通过这张图只能从表层上理解sandbox是一种安全体系,应用程序的所有操作都要通过这个体系来执行,其中核心内容是:sandbox对应用程序执行各种操作的权限限制。

93.不更新版本的方式添加新特性(热更新)。

html5?

1.使用FaceBook的开源框架reactive native,使用js写原生的iOS应用。iOS app可以在运行时从服务器拉取最新的js文件到本地,然后执行,因为js是一门动态的脚本语言,所以可以在运行时直接读取js文件执行,因此能够实现iOS的热更新。

2.使用lua脚本。lua脚本如同js一样,也能在运行时去读取lua脚本并执行。

3.Xcode6之后,苹果开放了iOS的动态库编译权限。所谓的动态库,其实就是可以在运行时加载。可以利用这个实现iOS的热更新。能够从沙箱里面读取到代码文件,就意味着可以在线更新代码,远程升级

94.请写一个类似于NSMutableArray的类,可以添加,删除,以及如何以最快的速度查找某个元素?

采用一个链表加一个数组的组合。添加删除用链表,查找用数组。

95.如果在发送异步请求的情况下,当前的界面删除了,会出现什么后果,如何解决?

遇到这种情况程序会崩溃,因为当前界面释放的同时,在当前界面所定义的对象也会释放,会出现野指针的情况,解决的办法是将异步请求的对象保持到单例中,这样界面释放的同时异步请求的对象还存在。

96.怎么用c++ 实现kvo?

开启一个新线程去轮询监听事件,并传入响应方法,如果事件发生就调用监听响应方法。

97.你会如何储存用户的认证信息?

使用keychain来存储,也就是钥匙串。 使用keychain需要导入Security框架。 

只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷贝到我们项目,并导入Security.framework 。KeychainItemWrapper的用法:

/** 初始化一个保存用户帐号的KeychainItemWrapper */ 

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number" accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"];

//保存数据 

[wrapper setObject:@"<帐号>" forKey:(id)kSecAttrAccount]; 

[wrapper setObject:@"<帐号密码>" forKey:(id)kSecValueData];

//从keychain里取出帐号密码 

NSString *password = [wrapper objectForKey:(id)kSecValueData];

98.堆和栈的区别

栈区(stack)由编译器自动分配释放 ,存放方法(函数)的参数值, 局部变量的值等,栈是向低地址扩展的数据结构,是一块连续的内存的区域。即栈顶的地址和栈的最大容量是系统预先规定好的。 

堆区(heap)一般由程序员分配释放, 若程序员不释放,程序结束时由OS回收,向高地址扩展的数据结构,是不连续的内存区域,从而堆获得的空间比较灵活。 

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出. 

分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。 

分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。 

全局区(静态区)(static),全局变量和静态变量的存储是放在一块 的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。 

文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。 

程序代码区—存放函数体的二进制代码

99.OC有多继承吗?没有的话用什么代替?

OC中没有多继承,可以用委托代理Protocol来实现。

100.MD5和Base64的区别是什么,各自场景是什么?

md5 用户密码存储 文件校验 

base64 公开的代码加密 url加密

101.SDWebImage原理

从内存中(字典)找图片(当这个图片在本次程序加载过),找到直接使用; 

从沙盒中找,找到直接使用,缓存到内存。 

从网络上获取,使用,缓存到内存,缓存到沙盒。

102.请问push view controller 和 present view controller有什么区别?

要是用push view controller ,首先必须确保根视图是NavigationController,不然是不可以用的。

push与present都可以推出新的界面。 

present与dismiss对应,push和pop对应。 

present只能逐级返回,push所有视图由视图栈控制,可以返回上一级,也可以返回到根vc,其他vc。 

present一般用于不同业务界面的切换,push一般用于同一业务不同界面之间的切换。

103.麻烦你设计个简单的图片内存缓存器

写一个FIFO的存储机制,设置一定量的内存大小。每次添加新的图片后检查是否超出容量,如果超出则释放队列最前面的图片。

缓存机制:FIFO, 先入先出 

设置内存:5M 

设置键数组:按时间先后顺序把键添加到数组里,NSMutableDictionary里按图片的键存储图片数据。 

提取缓存:根据键去NSMutableDictionary里获取图片数据。 

删除混存:缓存内存不够的时候,取键数组里第一个键,然后依据这个键去删除对应的数据,去出的键也从键数组里删除。

104.TCP/IP层次架构,每层的作用与协议;TCP拥塞控制;滑动窗口是怎么设计的,有什么好处

自我介绍

技术:我是电子科大的一名研二学生,我很喜欢编程,14年9月份开始接触iOS开发,15年3月到6月份在触及科技有限公司实习,负责OS开发。15年6月到9月份在教研室完成主尚艺术机构联盟这个 iOS App的开发和上线。

项目介绍

来福:来福是一款商户信息平台软件,加盟了来福的商户的各种信息会在来福中展示出来提供给消费者。来福会为用户展示一些每日推荐,商户福利这样的信息,查看商户评价,对商户进行评价和打分,按区域搜索附近商户,也可抽取一些商户劵,就类似美团一样。

主尚艺术机构联盟:主尚一款艺术品租赁平台软件,艺术家上传自己的作品,普通用户和游客都能够去浏览和查看。对艺术品都能进行评价,满意的可以选择租赁下来。平台每天展示出优秀的作品和热门的艺术家,提供搜索功能让用户按喜好去搜索作品和艺术家。

用户类型分三种,签约艺术家,游客,普通注册用户。艺术家相比普通注测用户多的一个权限就是能够上传作品,其他权限像发表评论,收藏作品,浏览作品,关注艺术家,租赁艺术品等权限都具备。游客不需要登陆,只具备浏览作品和查看评论的权限。

把面试官往你准备好的方向引导

工作套路

1.需求分析-技术选型-策略优化

2.对自己程序进程的一个评估和要求,要知道需要做到什么程度,规模确定是多大,适用人群是哪些 

3.挑选相应的第三方库,看是否满足要求,不满足要求可以用哪些替代,是否需要进行二次封装 

4.策略上还需要怎样对程序进行优化,例如内存

向技术面提问

(1) 投递简历的时候看到职位描述比较抽象,您能否具体描述一下,这个岗位具体需要是完成什么工作的,具体分工大概是怎样的?比如您可以说说您平时的工作大致是什么呢? 

(2) 您可以对我刚刚的表现做一个评价,指出我有哪些不足的地方吗?

向HR提问

贵公司XXX业务发展很好,这是公司发展的重点么?

怎么看待业务和技术

贵公司一般的团队的规模有多大,几个人负责一个产品或者业务?

贵公司的开发中是否会使用到一些最新技术?

对新人有没有什么培训,会不会安排导师?

你觉得我有哪些需要提高的地方?

还有就是遇到智力题的时候,不要什么都不说,面试官其实不是在看你的答案,而是在看你的逻辑思维,你只要说出你自己的见解,有一定的思考过程就行。

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

推荐阅读更多精彩内容

  • 1、OC中创建线程的方法是什么?如果指定在主线程中执行代码?如何延时执行代码。【难度系数★★】 1)创建线程的方法...
    木旁_G阅读 1,875评论 2 16
  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,036评论 29 470
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • Writing something to make me glad. 1风雨骤来。这地区的夏季总是多风多雨,瞬间飞...
    云居雁阅读 258评论 0 0
  • 去年无意间参加了一个理财班之后,开始自发学习起理财投资的知识,有事没事逛逛雪球,看看公号,听听微课,有一搭没一搭的...
    方闲闲阅读 240评论 0 1