一、关于深拷贝和浅拷贝的总结
理解
- 本质上我认为区别在于复制是是指针复制(浅拷贝)还是复制到新的地址上(深拷贝)
实际应用(yltest中有具体代码)
* 大体上会区分为对象和容器两个概念,对象的copy是浅拷贝,mutablecopy是深拷贝。
- 容器包含对象的拷贝,无论是copy,还是mutablecopy都是浅拷贝,要想实现对象的深拷贝,必须自己提供拷贝方法
- 非容器不可变对象:NSString
```
1. 对于非容器不可变对象的copy为浅拷贝,mutableCopy为深拷贝
2. 浅拷贝获得的对象地址和原对象地址一致, 返回的对象为不可变对象
3. 深拷贝返回新的内存地址,返回对象为可变对象
```
- 非容器可变对象: NSMutableString
```
对于可变对象的的拷贝,无论是copy还是mutabelCopy,都为深拷贝,且拷贝后返回的对象也是可变的
```
- 容器类不可变对象: NSArray
```
1.容器类不可变对象 copy只是指针copy ,mutableCopy,容器内是地址重新copy是深拷贝
2.但是容器内的对象无论是可变与不可变对象都是浅拷贝
```
- 容器类可变对象: NSMutableArray
```
1.容器类可变对象 copy和mutableCopy是深拷贝
2.但是容器内的对象无论是可变与不可变对象都是浅拷贝
```
小结:copy: 对于可变对象为深拷贝,对于不可变对象为浅拷贝; mutableCopy:始终是深拷贝,所谓拷贝,本质上是持有指针(无论是新的地址还是原来的地址);此外对可变容器赋值时,如果没有使用copy进行赋值,者修改其中一个内容时,其他内容会被修改(思考方向可以从引用指针和引用指针计数上开始)。不可变容器则不受影响.
自定义类对象的深浅拷贝
在OC中不是所有的类都支持拷贝,只有遵循<NSCopying>才支持copy,只有遵循<NSMutableCopying>才支持mutableCopy。如果没有遵循,拷贝时会直接Crash。
遵守协议以后,无论是copy还是mutableCopy,对于对象而言都是深拷贝;对对象内的属性重新赋值,不会改变其他对象的属性的值,因为赋值本质上来说是赋予新对象的属性指针
###关于属性得补充
```
@property (nonatomic ,strong) NSArray *array;
-(void)propertyTest {
NSArray *array = @[ @1, @2, @3, @4 ];
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array];
self.array = mutableArray;
NSLog(@"array :%@, mutableArray: %@,array object_p: %p,object_p: %p",self.array ,mutableArray,self.array ,mutableArray);
[mutableArray removeAllObjects];
NSLog(@"array :%@, mutableArray: %@,array object_p: %p,object_p: %p",self.array ,mutableArray,self.array ,mutableArray);
}
```
结果
```
2018-03-02 11:57:28.028222+0800 YLAudioFrequecy[1446:2312615] array :(
1,
2,
3,
4
), mutableArray: (
1,
2,
3,
4
),array object_p: 0x144d8d150,object_p: 0x144d8d150
2018-03-02 11:57:28.028532+0800 YLAudioFrequecy[1446:2312615] array :(
), mutableArray: (
),array object_p: 0x144d8d150,object_p: 0x144d8d150
```
如果没有使用[mutableArray copy](深拷贝);而直接使用self.array = mutableArray;因为实际上array是被赋值了mutable属性;
移除时值会被消除;
二、内存泄漏的一些想法
总的来说,我认为内存泄漏的原因是由于内存在ARC环境下没有被系统自动释放(如循环引用)
记录如何调试内存泄漏的blog
内存之定时器
我们都知道定时器使用完毕时需要将其停止并滞空,但**置空定时器**方法到底何时调用呢?在当前类的dealloc方法中吗?并不是,若将置空定时器方法调用在dealloc方法中会产生如下问题,**当前类销毁执行dealloc的前提是定时器需要停止并滞空**,**而定时器停止并滞空的时机在当前类调用dealloc方法时**,这样就造成了互相等待的场景,从而内存一直无法释放。因此需要注意**置空定时器**的调用时机从而避免内存无法释放,可以将**置空定时器**方法外漏,在外部调用即可。
内存之block
Block的内存泄漏主要是由于循环引用;防止内存泄漏就是要防止对象之间引用的闭环出现;
一般采用的方法是让其中一个对象持有另一个对象的弱引用,例如:
```
__weak typeof(self) weakself = self;
```
内存泄漏之delegate
```
@property (nonatomic, weak) id<****delegate> delegate;
```
比较值得注意的是swift中的协议要继承与class的,这时候可以用weak来修饰
特别之非OC对象
CGImageRef类型变量非OC对象,其需要手动执行释放操作
CGImageRelease(ref),否则会造成大量的内存泄漏导致程序崩溃。其他的对
于CoreFoundation框架下的某些对象或变量需要手动释放、C语言代码中的
malloc等需要对应free等都需要注意。
地图之内存泄漏
若项目中使用地图相关类,一定要检测内存情况,因为地图是比较耗费
App内存的,因此在根据文档实现某地图相关功能的同时,我们需要注意内存
的正确释放,大体需要注意的有需在使用完毕时将地图、代理等滞空为nil,注
意地图中标注(大头针)的复用,并且在使用完毕时清空标注数组等。
循环数量巨大时内存管理
```
for (int i = 0; i < 100000; i++) {
@autoreleasepool {
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@", string);
}
}
```
在循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。
三、Xcode中将图片放入assets.xcassets和直接拖入的区别
- 在mainBundle里面Xcode会生成一个Assets.car文件,将我们放在Images.xcassets的图片打包在里面。这里会有压缩,但是直接拖入(相当于直接将图片放入了mainBundle里面)的不会有压缩,所以程序打包出来会大一点
- 无论是通过imageNamed:来加载图片,还是直接在Storyboard的UIImageView里面设置图片,并且无论图片是jpg格式还是png格式,都不需要写后缀名;而拖入的图片:如果在Storyboard的UIImageView设置图片,那么需要明确地写上后缀名。(无论是.png还是.jpg都要写)在使用imageNamed:加载图片时,如果是.png格式,则不需要使用后缀名;如果是.jpg格式,则必须要写上后缀名。
- 放在Images.xcassets的图片不能通过imagesWithContentsOfFile:来加载。(因为这个方法相当于是去mainBundle里面找图片,但是这些图片都被打包进了Assets.car文件)
- 存放在.xcassets更方便与资源管理,例如更换图片时并需要修改名称,只需要简单的替换图片资源即可。
- 无需为不同像素的图片分别明明,系统会自动排列并且自动选择相应的图片。