1.堆和栈的区别?
管理方式:
对于栈来说,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak(内存泄漏)。
申请大小:
栈:在Widows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在Widows下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请空间超过栈的剩余空间时,将提示overflow(溢出)。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于操作系统是用链表示来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以致于永远都不可能有一个内存块从栈中间弹出
分配方式:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
总结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,吃完之后还得清洗、打扫等后续工作(不然用完了不清洗就不好再用),但是比较符合自己的口味,而且自由度大
2.static 关键字的作用?
1)函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值
2)在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其他函数访问;
3)在模块内的 static 函数只可被这一模块内其他函数调用,这个函数的使用范围被限制在声明它的模块内;
4)在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
5)在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的 static 成员变量
3.写一算法进行排序 {9,4,2,6,1,3,5}
NSArray *array = @[@9,@4,@2,@6,@1,@3,@5]; NSMutableArray *mArray = [NSMutableArray array]; for (int i = 0; i<array.count; i++) { [mArray addObject:array[i]]; } NSLog(@"排序前%@",mArray); for (int i = 0; i<mArray.count-1; i++) { for (int j = 0; j<mArray.count-1-i; j++) { NSString *first = mArray[j]; NSString *secend = mArray[j+1]; if ([first compare:secend] == NSOrderedDescending) { [mArray exchangeObjectAtIndex:j withObjectAtIndex:j+1]; } } } NSLog(@"排序后%@",mArray);
1.类和类的扩展的区别?
category和extensions的不同在于后者可以添加属性。另外后者添加的方法是必须要实现的
extensions可以认为是一个私有的category
2.Objcetive-C的类可以多重继承吗?可以实现多个接口嘛?Category 是什么?
Objective-C不可以实现多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;Category是类别,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。
3.Object-C属性特征(assign, retain, copy, readonly, readwrite, atomic, nonatomic)
1)assign:赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
2)retain:表示持有特性,setter方法将传入参数先保留,再赋值,传入参数时retainCount会+1;
3)copy:表示赋值特性,setter方法将传入对象复制一份,需要完全一份新的变量时;
4)readonly:只读特性,只会生成getter方法,不会生成setter方法,不希望属性在类外改变
5)readwrite:可读可写特性,需要生成getter方法和setter方法时
6)nonatomic:非原子操作,决定编译器生成的setter getter是否是原子操作;atomic表示多线程安全,一般使用nonatomic
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 = [str copy]; [name release]; name = str; }
Object-C的内存管理主要有三种方式:ARC(自动内存计数),MRC(手动内存计数),内存池。
1)ARC(自动内存技术):ARC就是在代码编译时为你自动在合适的位置插入release或autorelease,你只需要去申请内存,使用它,而不需要如何去释放它,系统会帮你解决,ARC比MRC节省了大量代码,使得开发效率更高,iOS5/Mac OS X 10.7开始导入,ARC不同于垃圾回收机制
2)MRC(手动内存技术):就是说从一段内存被申请之后,就存在一个变量用于保存这段内存被使用的次数,我们暂时把它称为计数器,当计数器变为0的时候,那么就是释放这段内存的时候。比如说,当在程序A里面一段内存被成功申请完成之后,那么这个计数器就从0变成1(我们把这个过程叫做alloc),然后程序B也需要使用这个内存,那么计数器就从1变成2(我们把这过程叫做retain)。紧接着程序A不再需要这段内存了,那么程序A就把这个计数器减1(我们把这个过程叫做release)。程序B也不需要这个内存的时候,那么也把计数器减1(这个过程还是release)。当系统(也就是Foundation)发现这个计数器变成0了,那么就会调用内存回收程序把这段内存回收(我们把这个过程叫做dealloc)。如果没有Foundation,那么维护计数器,释放内存等工作需要你手工来完成。解决:一般是由类的静态方法创建的,函数名中不会出现alloc或init字样,如[NSString string]和[NSArray arratWithObject:],创建后引用计数+0,在函数出栈后释放,既相当于一个栈上的局部变量,当然也可以通过retain延长对象的长存期。
3)内存池:可以通过创建和释放内存池控制内存申请和回收的时机。解决:是由autorelease加入系统内存池,内存池是可以嵌套的,每个内存池都需要有一个创建释放对,就像main函数中写的一样。使用也很加单,比如[[[NSString alloc] initWithFormat:@"Hey you!"] autorelease],即将一个NSString对象加入到最内层的系统内存池,当我们释放这个内存池时,其中的对象都会被释放。
ARC和MRC的区别
其实arc 内部机制原理也是来源于mrc ,arc 是在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。arc的首要目的就是让代码简洁化,编程简单化,开发更顺心应手,减少不必要的小问题小疏忽;顾名思义,自动引用计数管理,关于内存的申请,使用和释放过程都交给系统自动实现,我们可也不用关系里面的过程,但是事实上还是mrc的原理,只是是系统帮我们做了管理;
mrc,手动引用计数器管理,是在我们申请到某一块内存,在使用之后,要手动释放,释放机理涉及到计数器问题,如果未释放内存,会造成内存的浪费,俗称内存泄露,甚至引起很多未知的错误结果,这对程序有威胁很大,但是,何时释放,怎么释放,注意哪些问题,很有讲究,这就是mrc的不便之处,也是苹果推出arc的缘由;
mrc的具体机理,计数器是什么,在程序过程中的变化,在达到什么程度会释放内存,怎么操作;建议查阅相关文档;
mrc ,在代码上下形式主要表现为,调用该对象时,要做retain操作,使用完成后要release,最后还要重写dealloc方法,对该类的所有对象做释放,所以在mrc的代码会有autorelease,retain,release等词语,
而arc不允许有这些词汇,应为这些操作都由系统自动完成。
引用计数器
1.和内存管理相关的方法
1)alloc 引用计数器自动设为1
2)retain 引用计数器+1 返回了经过+1以后的当前实例对象
3)release 引用计数器-1,并不一定是释放
4)retainCount 获取引用计数器的值
5)dealloc 当实例对象被销毁之前,系统自动调用。
一定要调[super dealloc]
和内存管理相关的名词
1)僵尸对象:此对象被销毁,不能再使用,不能给它发送任何消息
2)野指针:指向僵尸对象(不可用的内存)的指针,给野指针发送消息将会产生不可控的后果。
3)空指针:没有指向任何对象的指针,给空指针发消息不会产生任何行为
内存管理原则
1.如果你想持有某个对象,就必须负责让做一次retain操作,引用计数器+1.
2.如果你想放弃对某个对象的持有权,就要负责让其做一次release操作,引用计数器-1.
3.谁retain,谁release
6.介绍一下协议 与 类别
类别:有时候我们需要在一个已经定义好的类中增加一些方法,而不是想去重写该类。比如,当工程已经很大,代码量比较多,或者类中已经包住很多方法,已经有其他代码调用了该类创建对象并使用该类的方法时,可以使用类别对该类扩充新的方法。
注意:类别只能扩充方法,而不能扩充成员变量。
协议:协议(protocol)类似于java语言里的接口(interface),定义了一组方法,而不提供具体实现,只有那些"遵守"(conform to)或"采用"(adopt)了这些Protocol的类来给出自己的实现。协议不是类本身,它们仅定义了其它对象有责任实现的接口。当在自己的类中实现协议的方法时,用户的类就是遵守这个协议的,协议声明的方法可以被任何一个类实现。
7.委托(代理)有什么作用?代理怎么实现,请简单代码举例?
委托(代理)作用:委托(代理)的作用有两个,一个是传值,一个是传事件。
1)传值就是在B类要把自己的一个数据或者对象传给A类,让A类去展示或者处理。(这个作用在两个View视图之间传递参数的时候特别有用)
2)传事件就是A类发生了什么事,把这事件告诉关注自己的人,也就是委托的对象,由委托的对象去考虑发生这个事件后应该做出什么反映。简单的说,假如A类发生了某个事件,它本身并不出来,而是通过委托delegate的形式,让它的委托对象B类去处理(当然委托对象B就要实现委托中的方法)。
实现:
在.h文件
@protocol EveryFrameDelegate<NSObject> -(void)DoSomethingEveryFrame; @end @property(nonatomic,assign)id<EveryFrameDelegate>delegate;
8.描述一个你遇到过的 retain cycle例子
9.#import 和 #include 的区别 @class
#import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动导入一次,不会重复导入,相当于#include和#pragma once;@class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;#import<>用来包含系统的文件,#import""用来包含用户头文件
10.在一个对象的方法里面:self.name = @“object” 和 _name = @“object”有什么不同
self.name = @"object"会调用对象的setName()方法;
_name = @"object"会直接把object赋值给当前对象的name属性
11.请简述 self.name = nil 的机制,以及与[_name release]的区别
self.name = nil;使用nil参数调用setName:方法
[_name release] 生成的访问器将自动释放以前的name对象
12.请解释一下 iOS应用的沙盒机制
iOS中的沙盒机制(sandBox)是一种安全体系,它规定了应用程序只能在为该应用创建的文件夹内读取文件,不可以访问其他地方的内容。所有的非代码文件都保存在这个地方,比如图片、声音、属性列表和文本文件等、
1)每个应用程序都在在即的沙盒内
2)不能随意跨越自己的沙盒去访问别的应用程序沙盒的内容
3)应用程序向外请求或接收数据都需要经过权限认证
13.Object-C中的数据类型有哪些,简述他们与基本数据类型的区别
Objective-C的数据类型有NSString、NSNumber、NSArray、NSMutableArray、NSData等待,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSObject的子类。NSInteger是基本数据类型int或者long的别名,它的区别在与,NSInteger会根据系统是32位还是64位来决定本身是int还是long。
14.iOS UI 的图像存储类型是什么
图像一般都存储为NSData类型
15.这段代码有什么问题?
-(void)setName:(NSString *)newName{
self.name = newName;
}
死循环
16什么时候用 NSMutableArray? 什么时候使用 NSArray?
NSArray创建的是静态数组,一旦创建之后,就再也不能添加和删除数组中的对象了
NSMutableArray创建的是动态数组,可随意添加或删除数组中的元素
什么时候该用哪个,看工程需求