iOS 9月16京东面试总结

1.blcok相关知识?

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

//block拷贝到堆上的几种情况:

    1.调用block的copy实例方法

    2.Block作为函数返回值

    3.将block赋值给有__strong修饰符的id类型的类或block类型成员变量时

    4.在方法名中含有usingBlock的cocoa框架方法或GCD的API传递blokc时<code>

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

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

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

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

此处指的不捕获自动变量,变量不包含全局变量,因为全局变量的特殊生命周期,不需要捕获,也可以在block中访问。

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

指针指向的值:

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方法返回的对象都是不可变对象。

在修改原值之前,marry1、marry2、marr3 地址都不一样,很明显copy和mutableCopy都是深拷贝,但是从修改原值后的打印结果来看,这里的深拷贝只是单层深拷贝:新开辟了内存地址,但是数组中的值还是指向原数组的,这样才能在修改原值后,marry2 marr3中的值都修改了。另外,从打印的数组元素地址可以很明显的看出来,修改前后marry1、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 消息,并且自身也会被销毁。

一、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的简单封装,所以自动释放机制的核心就在于这个类。

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

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,133评论 0 12
  • 把网上的一些结合自己面试时遇到的面试题总结了一下,以后有新的还会再加进来。 1. OC 的理解与特性 OC 作为一...
    AlaricMurray阅读 2,538评论 0 20
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述? 设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类...
    司马DE晴空阅读 1,277评论 0 7
  • 最近我又梦见他了,他是我的爷爷,一个高傲又和蔼可亲的人。 在农村,五六十年代的人无论生活多艰辛,都希望多子多福,晚...
    99_5aa2阅读 884评论 0 9