一、简单介绍
其实NSMutableArray的扩容的话应该就是在于如果其容量不够了,就会去重新malloc一块新的区域,然后会复制旧的数据到新的区域,之后把旧的空间给free掉。
下面我们就先去查看下NSMutableArray的对象的内存信息
以及下面的那个就是指向第一个数据的指针的地址信息,
所以下面我们再去读取从它开始的100个字节的内存信息
上面的0x01000020b0其实就是Milk字符串的地址信息,通过lldb的po命令,根据地址把对象给打印出来
二、扩容机制
上面提到了指向数据的指针的指针,其实这个指针所指向的内容在数组容量不够的时候是会发生变化的,我们可以去创建分类然后写入下面这个方法,就可以实时的观察这个指针所指向内容的变化
-(void *)dataAddress
{
void * address = (__bridge void *)self;
//void ** 指向指针的指针,指针类型占据8个字节,+2就是往下挪16个字节 这里用*((long *)address +2)也是可以的
return *((void **)address +2);
}
这个时候我们把数组的容量变为2,再去观察,观察后我们发现其实发生了频繁的改变的,只是扩容的规律还没有找到,不过也正好可以验证上面的NSMutableArray扩容的机制的说法。
三、实现数组扩容机制
在这篇文章中讲了下数组的实现,这里实现可变数组主要就是针对其内部的一个listInsert方法进行操作
/**插入数据*/
void listInsert(LinearList *list,int index,LinearListNodeValue value)
{
if(list==NULL||index < 0||index > list->length)
{
return;
}
//可变数组进行扩容操作
if(list->length == list->capacity)
{
//创建新的容量
int newCapacity = list->capacity*2;
//进行分配新的空间
LinearListNodeValue *newValues = malloc(sizeof(LinearListNodeValue *)*newCapacity);
//如果没有连续的存储空间,malloc也有可能失败。所以这里我们需要判断下
if(newValues == NULL)
return;
//进行旧数据的拷贝到新的空间
/*
参数1:目标地址
参数2:源地址
参数3:字节数
memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
*/
memcpy(newValues, list->values, sizeof(LinearListNodeValue)*list->capacity);
//释放旧的空间
free(list->values);
list->values = newValues;
//修改容量属性
list->capacity = newCapacity;
}
//从index开始到后面所有的数据都要进行挪动
for(int i=list->length-1;i>=index;i--)
{
list->values[i+1] = list->values[i];
}
//设置新的值到index的位置
list->values[index] = value;
//数组的数量增加
list->length++;
}
测试函数
void test3()
{
//创建一个结构体,返回一个结构体
LinearList * list = listCreat(2);
//添加数据
for(int i=0;i<20;i++)
{
listAdd(list, (LinearListNodeValue)i);
//list代表的是结构体的地址,void ** 代表的也是8个字节,所以+1就可以了跳过了前面的长度和容量的内存,最前面的*表示取出这个指针指向的地址
NSLog(@"数组长度:%d 数据地址:%p",listLength(list),*((void **)list+1));
}
listPrint(list);
}
输出结果