1. 简略介绍下NSURLConnection类及+ sendSynchronousRequest:returningResponse:error:– initWithRequest:delegate:两个办法的区别?

答: NSURLConnection次要用于网络拜访,其中+ sendSynchronousRequest:returningResponse:error:是同步拜访数据,即以后线程会阻塞,并期待request的返回的response,而– initWithRequest:delegate:应用的是异步加载,当其实现网络拜访后,会通过delegate回到主线程,并其委托的对象。

2. 在我的项目什么时候抉择应用GCD,什么时候抉择NSOperation

答: 我的项目中应用NSOperation的长处是NSOperation是对线程的高度形象,在我的项目中应用它,会使我的项目的程序结构更好,子类化NSOperation的设计思路,是具备面向对象的长处(复用、封装),使得实现是多线程反对,而接口简略,倡议在简单我的项目中应用。
我的项目中应用GCD的长处是GCD自身非常简单、易用,对于不简单的多线程操作,会节俭代码量,而Block参数的应用,会是代码更为易读,倡议在简略我的项目中应用。

3. ViewController的didReceiveMemoryWarning怎么被调用

答:[supper didReceiveMemoryWarning];

4. 写一个setter办法用于实现@property(nonatomic, retain) NSString *name,写一个setter办法用于实现@property(nonatomic, copy) NSString *name

- (void)setName:(NSString *)str{    [str retain];    [_name release];    _name = str;}- (void)setName:(NSString *)str{    id t = [str copy];    [_name release];    _name = t;}

5. 对于语句NSString *obj = [[NSData alloc] init]; obj在编译时和运行时别离时什么类型的对象?

答: 编译时是NSString的类型;运行时是NSData类型的对象

作为一个ios开发者,遇到问题的时候,有一个学习的气氛跟一个交换圈子特地重要对本身有很大帮忙,众人拾柴火焰高 这是一个我的iOS交换群:711315161,分享BAT,阿里面试题、面试教训,探讨技术, 大家一起交流学习成长!心愿帮忙开发者少走弯路。

6. Object C中创立线程的办法是什么?如果在主线程中执行代码,办法是什么?如果想延时执行代码、办法又是什么?

答:线程创立有三种办法:应用NSThread创立、应用GCD的dispatch、应用子类化的NSOperation,而后将其退出NSOperationQueue;在主线程执行代码,办法是performSelectorOnMainThread,如果想延时执行代码能够用performSelector:onThread:withObject:waitUntilDone:

7. 浅复制和深复制的区别?

答:浅层复制:只复制指向对象的指针,而不复制援用对象自身。
深层复制:复制援用对象自身。

8. PerformSelecter

当调用 NSObject 的performSelecter:afterDelay:后,实际上其外部会创立一个 Timer 并增加到以后线程的 RunLoop 中。所以如果以后线程没有 RunLoop,则这个办法会生效。
当调用performSelector:onThread:时,实际上其会创立一个 Timer 加到对应的线程去,同样的,如果对应线程没有 RunLoop 该办法也会生效。

9. 优化你是从哪几方面着手?

一、首页启动速度
启动过程中做的事件越少越好(尽可能将多个接口合并)
不在UI线程上作耗时的操作(数据的解决在子线程进行,解决完告诉主线程刷新节目)
在适合的机会开始后台任务(例如在用户指引节目就能够开始筹备加载的数据)
二、页面浏览速度
json的解决(iOS 自带的NSJSONSerialization,Jsonkit,SBJson)
数据的分页(后端数据多的话,就要分页返回,例如网易新闻,或者 微博记录)
数据压缩(大数据也能够压缩返回,缩小流量,放慢反应速度)
内容缓存(例如网易新闻的最新新闻列表都是要缓存到本地,从本地加载,能够缓存到内存,或者数据库,依据状况而定)
延时加载tab(比方app有5个tab,能够先加载第一个要显示的tab,其余的在显示时候加载,按需加载)
算法的优化(外围算法的优化,例如有些app 有个 联系人姓名用汉语拼音的首字母排序)
三、操作晦涩度优化
Tableview 优化(tableview cell的加载优化)
ViewController加载优化(不同view之间的跳转,能够提前准备好数据)
四、数据库的优化
数据库设计下面的重构
查问语句的优化
分库分表(数据太多的时候,能够分不同的表或者库)
五、服务器端和客户端的交互优化
客户端尽量减少申请
服务端尽量做多的逻辑解决
服务器端和客户端采取推拉联合的形式(能够利用一些同步机制)
通信协议的优化(缩小报文的大小)
电量应用优化(尽量不要应用后盾运行)
六、非技术性能优化
产品设计的逻辑性(产品的设计肯定要合乎逻辑,或者逻辑尽量简略,否则会让程序员抓狂,有时候用了好大力量,才能够实现一个小小的逻辑设计问题)
界面交互的标准(每个模块的界面的交互尽量对立,合乎操作习惯)
代码标准(这个能够隐形带来app 性能的进步,比方 用if else 还是switch ,或者是用!还是 ==)
code review(保持code Review 继续重构代码。缩小代码的逻辑复杂度)

10. 什么状况应用 weak 关键字,相比 assign 有什么不同?

1.在ARC中,在有可能呈现循环援用的时候,往往要通过让其中一端应用 weak 来解决,比方: delegate 代理属性。
2.本身曾经对它进行一次强援用,没有必要再强援用一次,此时也会应用 weak,如自定义 IBOutlet 控件属性个别也应用 weak;当然,也能够应用strong。
IBOutlet连进去的视图属性为什么能够被设置成weak?
答:因为父控件的subViews数组曾经对它有一个强援用。
不同点
assign 能够用非 OC 对象,而 weak 必须用于 OC 对象。
weak 表明该属性定义了一种“非领有关系”。在属性所指的对象销毁时,属性值会主动清空(nil)

11. 用@property申明的 NSString / NSArray / NSDictionary 常常应用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?

答:用 @property 申明 NSString、NSArray、NSDictionary 常常应用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作(就是把可变的赋值给不可变的),为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。
1.因为父类指针能够指向子类对象,应用 copy 的目标是为了让本对象的属性不受外界影响,应用 copy 无论给我传入是一个可变对象还是不可对象,我自身持有的就是一个不可变的正本。
2.如果咱们应用是 strong ,那么这个属性就有可能指向一个可变对象,如果这个可变对象在内部被批改了,那么会影响该属性。
总结:应用copy的目标是,避免把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发送变动会无意间篡改不可变类型对象原来的值。

12. runtime如何实现weak变量的主动置nil?

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

13. runloop是什么/runloop的概念?

runloop是线程相干的根底框架的一部分。一个runloop就是一个事件处理的循环,用来不停的调度工作以及解决输出事件。其实外部就是do-while循环,这个循环外部一直地解决各种工作(比方Source,Timer,Observer)。应用runloop的目标是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。

14. UITableViewCell上有个UILabel,显示NSTimer实现的秒表工夫,手指滚动cell过程中,label是否刷新,为什么?

这是否刷新取决于timer退出到Run Loop中的Mode是什么。Mode次要是用来指定事件在运行循环中的优先级的,分为

  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,闲暇状态
  • UITrackingRunLoopMode:ScrollView滑动时会切换到该Mode
  • UIInitializationRunLoopMode:run loop启动时,会切换到该mode
  • NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode汇合
    苹果公开提供的Mode有两个
  • NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
  • NSRunLoopCommonModes(kCFRunLoopCommonModes)
    在编程中:如果咱们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)增加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。当咱们滚动的时候,也心愿不调度,那就应该应用默认模式。然而,如果心愿在滚动时,定时器也要回调,那就应该应用common mode。

15. NStimer准吗?谈谈你的认识?如果不准该怎么实现一个准确的NSTimer?

不准;不准的起因如下
1、NSTimer加在main runloop中,模式是NSDefaultRunLoopMode,main负责所有主线程事件,例如UI界面的操作,简单的运算,这样在同一个runloop中timer就会产生阻塞。
2、模式的扭转。主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultMode 和 UITrackingRunLoopMode。
当你创立一个 Timer 并加到 DefaultMode 时,Timer 会失去反复回调,但此时滑动一个ScrollView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。所以就会影响到NSTimer不准的状况。
PS:DefaultMode 是 App 平时所处的状态,rackingRunLoopMode 是追踪 ScrollView 滑动时的状态。
办法:
1、在主线程中进行NSTimer操作,然而将NSTimer实例加到main runloop的特定mode(模式)中。防止被简单运算操作或者UI界面刷新所烦扰self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
2、在子线程中进行NSTimer的操作,再在主线程中批改UI界面显示操作后果
-(void)timerMethod2 {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(newThread) object:nil];
[thread start];
}
-(void)newThread{
@autoreleasepool{
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showTime) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}

16. NSOperation 相比于 GCD 有哪些劣势?

GCD是基于c的底层api,NSOperation属于object-c类。ios 首先引入的是NSOperation,IOS4之后引入了GCD和NSOperationQueue并且其外部是用gcd实现的。
绝对于GCD:
1、NSOperation领有更多的函数可用,具体查看api。
2、在NSOperationQueue中,能够建设各个NSOperation之间的依赖关系。
3、有kvo能够监测operation是否正在执行(isExecuted)、是否完结(isFinished),是否勾销(isCanceld)。
4、NSOperationQueue能够不便的治理并发、NSOperation之间的优先级。
GCD次要与block联合应用。代码简洁高效。
GCD也能够实现简单的多线程利用,次要是建设个个线程工夫的依赖关系这类的状况,然而须要本人实现相比NSOperation要简单。
具体应用哪个,依需要而定。 从集体应用的感觉来看,比拟适合的用法是:除了依赖关系尽量应用GCD,因为苹果专门为GCD做了性能下面的优化。

17. 如何拜访并批改一个类的公有属性?

有两种办法能够拜访公有属性,一种是通过KVC获取,一种是通过runtime拜访并批改公有属性。

18. 如何捕捉异样?

1\. 在app启动时(didFinishLaunchingWithOptions),增加一个异样捕捉的监听NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);2\. 实现捕捉异样日志并保留到本地的办法void UncaughtExceptionHandler(NSException *exception){    //异样日志获取    NSArray  *excpArr = [exception callStackSymbols];    NSString *reason = [exception reason];    NSString *name = [exception name];    NSString *excpCnt = [NSString stringWithFormat:@"exceptionType: %@ \n reason: %@ \n stackSymbols: %@",name,reason,excpArr];    //日常日志保留(能够将此性能独自提炼到一个办法中)    NSArray  *dirArr  = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);    NSString *dirPath = dirArr[0];    NSString *logDir = [dirPath stringByAppendingString:@"/CrashLog"];    BOOL isExistLogDir = YES;    NSFileManager *fileManager = [NSFileManager defaultManager];    if (![fileManager fileExistsAtPath:logDir]) {        isExistLogDir = [fileManager createDirectoryAtPath:logDir withIntermediateDirectories:YES attributes:nil error:nil];    }    if (isExistLogDir) {        //此处可扩大        NSString *logPath = [logDir stringByAppendingString:@"/crashLog.txt"];        [excpCnt writeToFile:logPath atomically:YES encoding:NSUTF8StringEncoding error:nil];    }}

19. Object-c的类能够多重继承么?能够实现多个接口么?Category是什么?重写一个类的形式用继承好还是分类好?为什么?

答:Object-c的类不能够多重继承;能够实现多个接口,通过实现多个接口能够实现C++的多重继承;Category是类别,个别状况用分类好,用Category去重写类的办法,仅对本Category无效,不会影响到其余类与原有类的关系。

20. Category(分类),Extension(扩大)和继承的区别

答:1.分类
category原则上只能在现有类根底上增加新的办法(能增加属性的起因只是通过runtime解决无setter/getter的问题而已),类别中的办法没被实现编译器是不会有任何正告的,这是因为类别是在运行时增加到类中的
2.扩大
iOS中的extension就是匿名的分类,只有头文件没有实现文件。类扩大不仅能够减少办法,还能够减少实例变量(或者属性),只是该实例变量默认是@private类型的(应用范畴只能在本身类,而不是子类或其余中央),类扩大中申明的办法没被实现,编译器会报警,这是因为类扩大是在编译阶段被增加到类中的
3.继承
在iOS中继承是单继承,既只能有一个父类。在继承中,子类能够应用父类的办法和变量,当子类想对本类或者父类的变量进行初始化,那么须要重写init()办法 。父类也能够拜访子类的办法和成员变量

21. 简述内存分区状况

1).代码区:寄存函数二进制代码
2).数据区:零碎运行时申请内存并初始化,零碎退出时由零碎开释。寄存全局变量、动态变量、常量
3).堆区:通过malloc等函数或new等操作符动静申请失去,需程序员手动申请和开释
4).栈区:函数模块内申请,函数完结时由零碎主动开释。寄存局部变量、函数参数

22. 间接调用_objc_msgForward函数将会产生什么?

_objc_msgForward是 IMP 类型,用于音讯转发的:当向一个对象发送一条音讯,但它并没有实现的时候,_objc_msgForward会尝试做音讯转发。
间接调用_objc_msgForward是十分危险的事,如果用不好会间接导致程序Crash,然而如果用得好,能做很多十分酷的事。
一旦调用_objc_msgForward,将跳过查找 IMP 的过程,间接触发“音讯转发”,如果调用了_objc_msgForward,即便这个对象的确曾经实现了这个办法,你也会通知objc_msgSend:“我没有在这个对象里找到这个办法的实现”

23. 对于Run Loop的了解

  • RunLoop,是多线程的法宝,即一个线程一次只能执行一个工作,执行完工作后就会退出线程。主线程执行完即时工作时会持续期待接管事件而不退出。非主线程通常来说就是为了执行某一工作的,执行结束就须要偿还资源,因而默认是不运行RunLoop的;
  • 每一个线程都有其对应的RunLoop,只是默认只有主线程的RunLoop是启动的,其它子线程的RunLoop默认是不启动的,若要启动则须要手动启动;
  • 在一个独自的线程中,如果须要在解决完某个工作后不退出,持续期待接管事件,则须要启用RunLoop;
  • NSRunLoop提供了一个增加NSTimer的办法,能够指定Mode,如果要让任何状况下都回调,则须要设置Mode为Common模式;
  • 本质上,对于子线程的runloop默认是不存在的,因为苹果采纳了懒加载的形式。如果咱们没有手动调用[NSRunLoop currentRunLoop]的话,就不会去查问是否存在以后线程的RunLoop,也就不会去加载,更不会创立。

24. runtime如何通过selector找到对应的IMP地址?(别离思考类办法和实例办法)

1.每一个类对象中都一个对象办法列表(对象办法缓存)
2.类办法列表是寄存在类对象中isa指针指向的元类对象中(类办法缓存)
3.办法列表中每个办法构造体中记录着办法的名称,办法实现,以及参数类型,其实selector实质就是办法名称,通过这个办法名称就能够在办法列表中找到对应的办法实现.
4.当咱们发送一个音讯给一个NSObject对象时,这条音讯会在对象的类对象办法列表里查找
5.当咱们发送一个音讯给一个类时,这条音讯会在类的Meta Class对象的办法列表里查找

25. runtime 中,SEL 和 IMP 的区别

办法名 SEL – 示意该办法的名称;
IMP – 指向该办法的具体实现的函数指针,说白了IMP就是实现办法。

26.block底层实现

block实质是指向一个构造体的一个指针
运行时机制 比拟高级的个性 纯C语言
平时写的OC代码 转换成C语言运行时的代码
指令:clang -rewrite-objc main.m(能够打印验证)
默认状况下,任何block都是在栈外面的,随时可能被回收
只有对其做一次copy操作 block的内存就会放在堆外面 不会开释
只有copy能力产生一个新的内存地址 所有地址会产生扭转

27. TCP协定三次握手

TCP协定采纳了三次握手策略。用TCP协定把数据包送出去后,TCP不会对传送后的状况束之高阁,它肯定会向对方确认是否胜利送达。握手过程中应用了TCP的标记——SYN(synchronize)和ACK(acknowledgement)。发送端首先发送一个带SYN标记的数据包给对方。接收端收到后,回传一个带有SYN/ACK标记的数据包以示传播确认信息。最初,发送端再回传一个带ACK标记的数据包,代表“握手”完结。

28. @property 的实质是什么?

@property = ivar + getter + setter;
“属性” (property)有两大概念:ivar(实例变量)、getter+setter(存取方法)

29. KVC的底层实现?

当一个对象调用setValue办法时,办法外部会做以下操作:
1). 查看是否存在相应的key的set办法,如果存在,就调用set办法。
2). 如果set办法不存在,就会查找与key雷同名称并且带下划线的成员变量,如果有,则间接给成员变量属性赋值。
3). 如果没有找到_key,就会查找雷同名称的属性key,如果有就间接赋值。
4). 如果还没有找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:办法。
这些办法的默认实现都是抛出异样,咱们能够依据须要重写它们。

30. ViewController生命周期

依照执行顺序排列:
1). initWithCoder:通过nib文件初始化时触发。
2). awakeFromNib:nib文件被加载的时候,会产生一个awakeFromNib的音讯到nib文件中的每个对象。
3). loadView:开始加载视图控制器自带的view。
4). viewDidLoad:视图控制器的view被加载实现。
5). viewWillAppear:视图控制器的view将要显示在window上。
6). updateViewConstraints:视图控制器的view开始更新AutoLayout束缚。
7). viewWillLayoutSubviews:视图控制器的view将要更新内容视图的地位。
8). viewDidLayoutSubviews:视图控制器的view曾经更新视图的地位。
9). viewDidAppear:视图控制器的view曾经展现到window上。
10). viewWillDisappear:视图控制器的view将要从window上隐没。
11). viewDidDisappear:视图控制器的view曾经从window上隐没。

31. 如何用GCD同步若干个异步调用?(如依据若干个url异步加载多张图片,而后在都下载实现后合成一张整图)

// 应用Dispatch Group追加block到Global Group Queue,这些block如果全副执行结束,就会执行Main Dispatch Queue中的完结解决的block。// 创立队列组dispatch_group_t group = dispatch_group_create();// 获取全局并发队列dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_group_async(group, queue, ^{ /*加载图片1 */ });dispatch_group_async(group, queue, ^{ /*加载图片2 */ });dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); // 当并发队列组中的工作执行结束后才会执行这里的代码dispatch_group_notify(group, dispatch_get_main_queue(), ^{        // 合并图片});

32. dispatch_barrier_async(栅栏函数)的作用是什么?

函数定义:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);作用:    1.在它后面的工作执行完结后它才执行,它前面的工作要等它执行实现后才会开始执行。    2.防止数据竞争// 1.创立并发队列dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);// 2.向队列中增加工作dispatch_async(queue, ^{  // 1.2是并行的    NSLog(@"工作1, %@",[NSThread currentThread]);});dispatch_async(queue, ^{    NSLog(@"工作2, %@",[NSThread currentThread]);});dispatch_barrier_async(queue, ^{    NSLog(@"工作 barrier, %@", [NSThread currentThread]);});dispatch_async(queue, ^{   // 这两个是同时执行的    NSLog(@"工作3, %@",[NSThread currentThread]);});dispatch_async(queue, ^{    NSLog(@"工作4, %@",[NSThread currentThread]);});// 输入后果: 工作1 工作2 ——》 工作 barrier ——》工作3 工作4 // 其中的工作1与工作2,工作3与工作4 因为是并行处理先后顺序不定。

作者:72行代码 链接:iOS 面试题汇总