iOS 面试第三节 Foundation框架

所有的Mac OS X和IOS程序都是由大量的对象构成,而这些对象的根对象都是NSObject,NSObject就处在Foundation框架之中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.nil、NIL、NSNULL 、NULL有什么区别?

  1. nil、NIL可以说是等价的,都代表内存中一块空地址。
  2. NSNull代表一个指向nil的对象。
  3. Null是指针为空

{1} 对象赋值的时候 Object = nil; 表示我想把这个对象释放掉。或者经过某些原因,经多次release,引用计数为0,导致系统将这块内存释放掉,这个时候这个对象为nil,我称它为“空对象”。(注意:我这里强调的是“空对象”,下面我会拿它和“值为空的对象”作对比!!!)。对于这种”空对象“,所有关于retain的操作都会导致程序crash,例如可变数组添加此对象、字典中添加此对象都会本崩溃,但是调用此对象方法、查看此对象的属性是不会崩溃的,只是无法执行。个人理解为可以拿到这个PersonTest 类型的虚拟的实例,所以可以对这个虚拟的实例进行属性,方法调用只是不会奏效,但是由于内存中没有这个虚拟实例的内存所以涉及有关retain的内存管理时候,就会引起crash.

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSMutableArray *mutableArr = [NSMutableArray array];
    PersonTest *people = nil;
    people.name = @"小明";
    [people testGoMeth]; //此处不崩溃
    [mutableArr addObject:people];// 只有此处崩溃
}

{2}NSNull和nil的区别在于,nil是一个"空对象”,已经完全从内存中消失了,而如果我们想表达“我们需要有这样一个容器,但这个容器里什么也没有”的观念时,我们就用到NSNull,我称它为“值为空的对象”。如果你查阅开发文档你会发现NSNull这个类是继承NSObject,并且只有一个“+ (NSNull *) null;”类方法。这就说明NSNull对象拥有一个有效的内存地址,所以在程序中对它的retain引用都是不会导致程序崩溃的,但如果对这个实例里面属性、方法进行调用赋值是不可以的。个人理解为:指针指向的空间是存在一个实例对象,但是这个实例对象是空的,虽然实例对象类型还是PersonTest,但由于是一个对象值为空,所以不能对其进行读取,方法调用了。但是作为一个存在的空对象也是有内存的,所以是可以进行retain操作的。 参考代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSMutableArray *mutableArr = [NSMutableArray array];
    PersonTest *people = [NSNull null];
    people.name = @"小明";// 此处crash
    [people testGoMeth]; //此处crash
    [mutableArr addObject:people];// 此处不崩溃
}

{3}Nil
nil和Nil在使用上是没有严格限定的,也就是说凡是使用nil的地方都可以用Nil来代替,反之亦然。只不过从编程人员的规约中我们约定俗成地将nil表示一个空对象,Nil表示一个空类。

{4}我们知道Object-C来源于C、支持于C,当然也有别于C。而NULL就是典型C语言的语法,它表示一个空指针,参考代码如下:
int *ponit = NULL;

理解这个的时候需要首先搞明白什么是指针?
通俗点儿理解其实它就是就是一个存放地址的变量存储空间,当指针指向某个变量,这时这个指针里就存放了那个变量的地址。这就是我们常说的指针指向一个地址,意思是通过它能找到以它为地址的内存单元。利用指针我们可以直接获取变量中的值用,要是在指针前加 * 就是取其真值了(也就是被指向的变量的值)

举个例子:
如果一个整型变量int i,int* p=&i表示将 i 的地址存入整型指针变量即int*中 。

&i表示对i 取地址,返回值是i的地址。

假设i在内存中所存在的地址为xx0bd00a(随便写的)

也就是说 指针p中存放了xx0bd00a这个地址

当你操作这个p时就是直接操作了xx0bd00a这个地址中存放的东西,间接操作了变量i,这就是指针的作用。

那我们在看看内存是什么(其实上面已经描述很清楚了)?内存是实实在在的硬件,可以存放数据,地址是内存的标识,每一个地址都对应一个内存。所以内存和地址是一一对应密不可分的。
比如说内存就像一个个的小格子,每个格子的大小是一个字节,可以存放一个字节的数据,而指针地址呢,就是存放盒子标号的,我们得到指针,也就可以找到那个盒子了(当然也存在找不到的情况,那就是野指针和空指针,这里就不详细叙说了)。

野指针就是内存中变量搬家了,或者被系统释放了,从而导致你当前指针中取的这个地址找不到它了。

空指针就是这个指针的值为空Null。

2.如何实现一个线程安全的 NSMutableArray?

NSMutableArray是线程不安全的,当有多个线程同时对数组进行操作的时候可能导致崩溃或数据错误

  • 线程锁:使用线程锁对数组读写时进行加锁
    但是并不推荐这么做,对数组的读写都加锁,虽然数组是线程安全了,但失去了多线程的优势

  • 派发队列:在《Effective Objective-C 2.0…》书中第41条:多用派发队列,少用同步锁中指出:使用“串行同步队列”(serial synchronization queue),将读取操作及写入操作都安排在同一个队列里,即可保证数据同步。而通过并发队列,结合GCD的栅栏块(barrier)来不仅实现数据同步线程安全,还比串行同步队列方式更高效。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章