1. copy和mutablecopy。这个问题大家应该都遇到过,大多数面试官都会问到这个问题,或深或浅而已。
这个问题一般是从深浅拷贝延伸过来的,简单来说浅拷贝只是对指向对象的指针的拷贝,而深拷贝不仅是对指针的拷贝,同时也将对象本身进行拷贝。
copy:需要遵循NSCopying协议,是调用copyWithZone方法得到的一个不可变对象。自定义类需要实现NSCopying协议,并重写copyWithZone方法。
mutableCopy: 需要遵循NSMutableCopying协议,是调用mutableCopyWithZone方法得到的一个可变对象。自定义类需要实现NSMutableCopying协议,并重写mutableCopyWithZone方法。
下面我们先用一段测试代码来看看NSString和NSMutableString调用copy和mutuableCopy方法后对象的拷贝情况。
NSString *str = [[NSString alloc] initWithString:@"Hello"];
NSString *strCopy = [str copy];
NSString *strMutableCopy = [str mutableCopy];
NSLog(@" str pointer: %p",&str);
NSLog(@" strCopy pointer: %p",&strCopy);
NSLog(@"strMutableCopy pointer: %p",&strMutableCopy);
NSLog(@" str: %p",str);
NSLog(@" strCopy: %p",strCopy);
NSLog(@"strMutableCopy: %p",strMutableCopy);
NSMutableString *mutStr = [[NSMutableString alloc] initWithString:@"World"];
NSMutableString *mutStrCopy = [str copy];
NSMutableString *mutStrMutableCopy = [str mutableCopy];
NSLog(@" mutStr: %p",mutStr);
NSLog(@" mutStrCopy: %p",mutStrCopy);
NSLog(@"mutStrMutableCopy: %p",mutStrMutableCopy);
NSArray *arr = [NSArray arrayWithObjects:@"1",@"2", nil];
NSArray *copyArr = [arr copy];
NSArray *mutableArr = [arr mutableCopy];
NSLog(@"arr pointer: %p",&arr);
NSLog(@"copyArr pointer: %p",©Arr);
NSLog(@"mutableArr pointer: %p",&mutableArr);
NSLog(@"arr : %p",arr);
NSLog(@"copyArr : %p",copyArr);
NSLog(@"mutableArr : %p",mutableArr);
NSLog(@"arr0 : %p",arr[0]);
NSLog(@"copyArr0 : %p",copyArr[0]);
NSLog(@"mutableArr0 : %p",mutableArr[0]);
运行结果是:
str pointer: 0x7fff55b579a8
strCopy pointer: 0x7fff55b579a0
strMutableCopy pointer: 0x7fff55b57998
str: 0x10a0a9090
strCopy: 0x10a0a9090
strMutableCopy: 0x610000077380
mutStr: 0x60000007b500
mutStrCopy: 0x10a0a9090
mutStrMutableCopy: 0x60000007b200
arr pointer: 0x7fff55b57978
copyArr pointer: 0x7fff55b57970
mutableArr pointer: 0x7fff55b57968
arr : 0x61000002a880
copyArr : 0x61000002a880
mutableArr : 0x61000005f1a0
arr0 : 0x10a0a91f0
copyArr0 : 0x10a0a91f0
mutableArr0 : 0x10a0a91f0
由此可见:
classes | copy | mutableCopy |
---|---|---|
NSString | 浅拷贝,只是复制了指针 | 深拷贝,生成一个新的可变对象 |
NSMutableString | 深拷贝,生成一个新的不可变对象 | 深拷贝,生成一个新的可变对象 |
NSArray | 浅拷贝,只是复制了指针 | 深拷贝,生成一个新的可变对象 |
但是NSArray中的对象是没有被拷贝的,要想拷贝Array中的数据必须对每个对象进行拷贝,前提是对象必须遵守相应的协议。
2.instancetype和id的区别。
首先id类型的引入是因为要支持OC的动态类型;关于动态类型和静态类型后面再做介绍。
id类型可以指向任意一种指向类的对象,因此它既可以作为函数的参数类型,也可以作为返回值的类型。在编译时不会检查类型。
instancetype类型只能作为返回值类型,返回方法所在类相同类型的对象,在编译时会进行类型检查。
使用的过程中的建议就是构造方法全都使用instancetype类型。
3. 静态数据类型和动态数据类型
(1)静态数据类型的特点:
在编译时就知道变量的类型, 知道变量中有哪些属性和方法 在编译的时候就可以访问这些属性和方法, 并且如果是通过静态数据类型定义变量, 如果访问了不属于静态数据类型的属性和方法, 那么编译器就会报错
(2)动态数据类型的特点:
在编译的时候编译器并不知道变量的真实类型, 只有在运行的时候才知道它的真实类型, 并且如果通过动态数据类型定义变量, 如果访问了不属于动态数据类型的属性和方法, 编译器不会报错
4. autorelease 自动释放池
(1)什么是自动释放池?
autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
(2)自动释放池的优点是什么?
不需要再手动去管理对象生存周期,何时去进行release操作。
(3)简述自动释放池的原理?
autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该 Object放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用Release。
(4)自动释放池有哪些注意事项?
<1>在自动释放池中创建了对象, 一定要调用autorelease,才会将对象放入自动释放池中
<2>一个程序中可以创建N个自动释放池, 并且自动释放池还可以嵌套
<3>不要再自动释放池中使用比较消耗内存的对象, 占用内存比较大的对象
<4>尽量不要再自动释放池中使用循环, 特别是循环的次数非常多, 并且还非常占用内存
<5>千万不要写多次autorelease
<6>一个alloc/new对应一个autorelease或者release
(5)自动释放池是以什么形式存储的?
如果存在多个自动释放池的时候, 自动释放池是以 “栈” 的形式存储在堆区
5. ARC内存管理
(1):ARC的原理是什么?
当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease,而我们则完全不需要担心自己管理不好内存而导致内存泄漏等问题。
(2)ARC有什么优点?
免除了手动管理内存的烦琐,如果不错用的话基本上能够避免内存泄露
(3)ARC的原则是什么?什么是强指针?什么是弱指针?
只要还有一个强指针变量指向对象,对象就会保持在内存中
<1>强指针
默认所有指针变量都是强指针
被__strong修饰的指针
<2>弱指针
被__weak修饰的指针
(3)ARC下@property修饰符有哪些?
strong : 用于OC对象, 相当于MRC中的retain
weak : 用于OC对象, 相当于MRC中的assign
assign : 用于基本数据类型, 跟MRC中的assign一样
6. 如何解决block中的循环引用?
如果block内引用了对象本身,或者导致了A引用了B,B又引用了A的情形,导致两个对象互相引用,引用计数永远不能变成0而无法释放的情况。
解决循环引用可以在block对象外面设为weak:__weak __typeof(self) weakSelf = self;
如果block内的某些使用weakSelf的代码执行的比较晚,则weakSelf可能已经被释放了而导致崩溃,所以需要将weakSelf设为strong: __strong __typeof(self) strongSelf = weakSelf; strongSelf是一个自动变量当block执行完毕就会被释放掉,不会对self进行一直进行强引用。
7. 判断一个数是整数还是小数的小技巧
float a = 3.4;
if (a == (int)a) {
NSLog(@"is int");
}
else{
NSLog(@"not int");
}
输出 "not int"