iOS 四月份百度面试总结

1.blcok相关知识?面试

在ARC环境下,编译器会根据状况自动将栈上的block进行一次copy操做,将block复制到堆上。swift

//block拷贝到堆上的几种状况:数组

  1. 调用block的copy实例方法
  2. Block做为函数返回值
  3. 将block赋值给有__strong修饰符的id类型的类或block类型成员变量时
  4. 在方法名中含有usingBlock的cocoa框架方法或GCD的API传递blokc时<code>

咱们使用block有两种方式,逃逸和非逃逸(借用swift中的说法)。markdown

非逃逸:声明的block的生命周期就是声明所在的函数体的生命周期。咱们在函数体中声明一个block,这个block会在函数体结束时释放。网络

逃逸:声明的block生命周期和声明所在的函数体无关了。咱们在函数A中声明的block,在B中也能够调用。app

1.NSGlobalBlock (不捕获自动变量的类型或者捕获的是静态局部变量)框架

此处指的不捕获自动变量,变量不包含全局变量,由于全局变量的特殊生命周期,不须要捕获,也能够在block中访问。异步

1.值捕获:捕获的变量为其指针指向的值,或基础数据类型的值函数

指针指向的值:oop

2.地址捕获:捕获的变量为其指针自己,或指向基础数据类型的指针

4.解决循环引用,打破block对对象的强引用便可,两种方式:__weak对象,__block对象(需在block内将变量主动置空)

对于 MRC 环境,使用 Copy 修饰 Block,会将栈区的 Block 拷贝到堆区。

对于 ARC 环境,使用 Strong、Copy 修饰 Block,都会将栈区的 Block 拷贝到堆区。

因此,Block 不是必定要用 Copy 来修饰的,在 ARC 环境下面 Strong 和 Copy 修饰效果是同样的。

补充:一个block要使用self,会处理成在外部声明一个weak变量指向self,然而为什么有时会出如今block里又声明一个strong变量指向weakSelf?

缘由:block会把写在block里的变量copy一份,若是直接在block里使用self,(self对变量默认是强引用)self对block持有,block对self持有,致使循环引用,因此这里须要声明一个弱引用weakSelf,让block引用weakSelf,打破循环引用。

而这样会致使另一个问题,由于weakSelf是对self的弱引用,若是这个时候控制器pop或者其余的方式引用计数为0,就会释放,若是这个block是异步调用并且调用的时候self已经释放了,这个时候weakSelf已就变成了nil。

当控制器(也能够是其余的控件)pop回来以后(或者一些其余的缘由致使释放),网络请求完成,若是这个时候须要控制器作出反映,须要strongSelf再对weakSelf强引用一下。

可是,你可能会疑问,strongSelf对weakSelf强引用,weakSelf对self弱引用,最终不也是对self进行了强引用,会致使循环引用吗。不会的,由于strongSelf是在block里面声明的一个指针,当block执行完毕后,strongSelf会释放,这个时候将再也不强引用weakSelf,因此self会正确的释放。

2.数组的深拷贝和浅拷贝?

@property (nonatomic, strong) NSArray *array0;

@property (nonatomic, copy) NSArray *array1;

@property (nonatomic, strong) NSMutableArray *array2;

@property (nonatomic, copy) NSMutableArray *array3;

第一种写法不推荐使用,是对传递对象的强引用,不论是传递 NSArray 仍是 NSMutableArray 对象都是多了一个强引用的指针而已。当外面传递的是 NSMutableArray 对象,在该类中使用该属性时就要注意外面也可能随时修改该对象。

第二种写法为推荐写法,若是传递的是 NSArray 对象,则只是对原先对象的一份强引用(应该是编译器优化的),可是若是传递的是 NSMutableArray 对象,则是对原先对象的一次“单层深拷贝”,生成的 NSArray 对象是一份新内存地址的对象,可是其中的元素仍是原先的。

第三种写法为推荐写法,是对传递 NSMutableArray 对象的一个强引用。该类中使用该属性时要注意外面也可能随时修改该对象。

第四种写法为错误写法,是对传递 NSMutableArray 对象的一个“单层深拷贝”,并且生成的对象是 NSArray 类型而不是 NSMutableArray 类型,在该类中对该属性作增删操做就会出现unrecognized method send to … 引起crash。

NSString 与 NSMutableString 和上面的结论是同样的,只是没有单层深拷贝的概念。

3. 浅拷贝、单层深拷贝、深拷贝

浅拷贝

所谓的浅拷贝,就是指只是将对象内存地址多了一个引用,也就是说,拷贝结束以后,两个对象的值不只相同,并且对象所指的内存地址都是同样的。

单层深拷贝

对于不可变的容器类对象(如NSArray、NSSet、NSDictionary)进 mutableCopy 操做,内存地址发生了变化,可是其中的元素内存地址并无发生变化,属于单层深拷贝。

对于可变集合类对象(如NSMutableArray、NSMutableSet、NSMutableDictionary),不论是进行 copy 操做仍是 mutableCopy 操做,其内存地址都发生了变化,可是其中的元素内存地址都没有发生变化,属于单层深拷贝。

深拷贝

所谓深拷贝,就是指拷贝一个对象的具体内容,拷贝结束以后,两个对象的值虽然是相同的,可是指向的内存地址是不一样的。两个对象之间也互不影响,互不干扰。

对 NSArray 进行 copy 操做的时候,数组的内存地址没有发生变化,可是进行 mutableCopy 操做时,其内存地址发生了变化,结论跟非集合类的差很少。

可是,这里的深拷贝和非集合类的深拷贝仍是不太同样的,上面咱们打印出了数组的第一个元素的内存地址,能够发现,进行 mutableCopy 操做时,虽然数组内存地址发生了变化,可是数组元素的内存地址并无发生变化。

这个属于一个特例,咱们称它为单层深复制。并非理论上的彻底深复制。

对 NSMutableArray 进行 copy 和 mutableCopy 操做,其内存地址都发生了变化,可是,对于数组中的元素,不论是进行的哪一种操做,内存地址始终都没有发生变化,因此属于单层深拷贝。

因此,咱们能够得出,对于不可变的集合类对象进行 copy 操做,只是改变了指针,其内存地址并无发生变化;进行 mutableCopy 操做,内存地址发生了变化,可是其中的元素内存地址并无发生变化。

对于可变集合类对象,不论是进行 copy 操做仍是 mutableCopy 操做,其内存地址都发生了变化,可是其中的元素内存地址都没有发生变化,属于单层深拷贝。

深拷贝就是内容拷贝,浅拷贝就是指针拷贝。本质区别在于:

是否开启新的内存地址

是否影响内存地址的引用计数

特别注意的是:对于集合类的可变对象来讲,深拷贝并不是严格意义上的深复制,只能算是单层深复制,即虽然新开辟了内存地址,可是存放在内存上的值(也就是数组里的元素仍然之乡员数组元素值,并无另外复制一份),这就叫作单层深复制。

No1:可变对象的copy和mutableCopy方法都是深拷贝(区别彻底深拷贝与单层深拷贝) 。

No2:不可变对象的copy方法是浅拷贝,mutableCopy方法是深拷贝。

No3:copy方法返回的对象都是不可变对象。

在修改原值以前,marry一、marry二、marr3 地址都不同,很明显copy和mutableCopy都是深拷贝,可是从修改原值后的打印结果来看,这里的深拷贝只是单层深拷贝:新开辟了内存地址,可是数组中的值仍是指向原数组的,这样才能在修改原值后,marry2 marr3中的值都修改了。另外,从打印的数组元素地址能够很明显的看出来,修改先后marry一、marry、marr3的数组元素地址都是如出一辙的,更加佐证了这一点。

可是修改数组的元素的个数,只有当前数组的个数会改变,数组之间不会互相影响,修改元素的值会互相影响 ,全部的数组的元素的值都会改变

[mstr1 appendFormat:@"aaa"];这样修改元素的值,全部数组的元素都会修改。

[marry3 replaceObjectAtIndex:0 withObject:@"value1---"];这样修改元素的值,只有当前数组的元素会修改。

3.隐式动画和显式动画的区别?

显式动画是指用户本身经过beginAnimations:context:和commitAnimations建立的动画。

隐式动画是指经过UIView的animateWithDuration:animations:方法建立的动画。

动画事务--CATransaction

隐式动画一直存在 如需关闭需设置;显式动画是不存在,如需显式 要开启(建立)。

显式动画是指用户本身经过beginAnimations:context:和commitAnimations建立的动画。隐式动画是指经过UIView的animateWithDuration:animations:方法建立的动画。

隐式动画是系统框架自动完成的。Core Animation在每一个runloop周期中自动开始一次新的事务,即便你不显式的用[CATransaction begin]开始一次事务,任何在一次runloop循环中属性的改变都会被集中起来,而后作一次0.25秒的动画。在iOS4中,苹果对UIView添加了一种基于block的动画方法:+animateWithDuration:animations:。这样写对作一堆的属性动画在语法上会更加简单,但实质上它们都是在作一样的事情。CATransaction的+begin和+commit方法在+animateWithDuration:animations:内部自动调用,这样block中全部属性的改变都会被事务所包含

4.给对象赋值nil是作了什么操做?

nil在字典,数组中有特殊含义–元素结束标记

5.自动释放池的相关知识?

每个自动释放池都是由一系列的 AutoreleasePoolPage 组成的,而且每个 AutoreleasePoolPage 的大小都是 4096 字节(16 进制 0x1000)自动释放池中的 AutoreleasePoolPage 是以双向链表的形式链接起来的:

autorelease 方法

NSAutoreleasePool*pool = [[NSAutoreleasePoolalloc]init ];//建立一个自动释放池

Person *person = [[Person alloc]init];

//调autorelease方法将对象加入到自动释放池//注意使用该方法,对象不会本身加入到自动释放池,须要人为调用autorelease方法加入

[person autorelease];

//,手动释放自动释放池执行完这行代码是,自动释放池会对加入他中的对象作一次release操做

[pool release];

自动释放池销毁时机:[pool release]代码执行完后

每个自动释放池没有单独的结构,每个autorealeasePool对象都是由若干个个autoreleasePoolPage经过双向链表链接而成,当一个对象调用了autorelease方法,这个对象就会被加入到当前自动释放池的最新的autoreleasePoolPage中,关于autoreleasePoolPage/,请看下面

当咱们向自动释放池 pool 发送 release 消息,将会向池中临时对象发送一条 release 消息,而且自身也会被销毁。

1、autorelease 对象会在何时释放?

分两种状况:

使用 @autoreleasepool,会在大括号结束时释放

不使用 @autoreleasepool,这个会由系统自动释放,释放时机是在当前 runloop 结束时释放,由于系统会自动为每一个 runloop 执行自动释放池的 push 和 pop 操做

Autorelease对象何时释放?

这个问题拿来作面试题,问过不少人,没有几个能答对的。不少答案都是“当前做用域大括号结束时释放”,显然木有正确理解Autorelease机制。

在没有手加Autorelease Pool的状况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它可以释放的缘由是系统在每一个runloop迭代中都加入了自动释放池Push和Pop

ARC下,咱们使用@autoreleasepool{}来使用一个AutoreleasePool,随后编译器将其改写成下面的样子:

void *context = objc_autoreleasePoolPush();

// {}中的代码

objc_autoreleasePoolPop(context);

而这两个函数都是对AutoreleasePoolPage的简单封装,因此自动释放机制的核心就在于这个类。

相关文章
相关标签/搜索