七月最后的一天,选择开始新的一种生活。
开发了这几年,也没好好整理一下关于开发的知识,现在的技术日新月异,不过百变不离其宗,还好基础和思考的方式为主。
关于iOS,越来越多的人说日落西山,其实我想说的是,任何一样工作都有起伏,可只要你技术足够强大,总有你的一席之地,何况作为一名开发者,要具备学习能力,何惧,唯一惧怕的是少了激情,多了懒惰和借口。
关于iOS基础整理
越是简单的东西越是重要。
我还是很懒,把在网上整理的一些个人认为比较重要的基础。
类和对象
MRC 和 ARC (swift是在OC的基础上升级的,想知道更多基础还是先弄清楚OC)
1、内存几大区域
1> 栈区:局部变量(基本数据类型、指针变量)。
2> 堆区:程序运行的过程中动态分配的存储空间(创建的对象)。
3> BSS段:没有初始化的全局变量和静态变量。
4> 数据区:已经初始化的全局变量和静态变量。(字符串常量)
5> 代码段:程序编译后的代码的内容。
2、引用计数器
1> 引用计数器:每个继承自NSObject的对象都有一个引用计数器,用来表示当前对象有几个拥有者。
2> 引用计数器的作用:用来判断对象是否应该回收。
3> 引用计数器的操作(ARC下无法使用)
* retain 引用计数器+1
*release 引用计数器-1
*retainCount 得到引用计数器的值(点击进入NSObject.h文件,有一个- (NSUInteger)retainCountOBJC_ARC_UNAVAILABLE 的方法)
注:任何一个OC对象,只要一被创建出来,其引用计数默认为1;一个对象的引用计数归0的时候,对象就会被销毁。
3、关于dealloc方法
1> 对象被释放时会自动调用
2> 开发中经常重写对象的dealloc方法,用于观察对象什么时候被释放或者想要在对象释放之前做些相应的操作,dealloc方法可以看做是对象的“临终遗言”。
3> 在MRC下,重写dealloc要注意必须要在其最后调用[super dealloc]。
4、僵尸对象、野指针、空指针。
1> 僵尸对象:即指已经被销毁的对象(不能再使用的对象)
2> 野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报“EXC_BAD_ACCESS"错误(常见错误)。
3> 空指针:没有指向存储空间的指针(nil),给空指针发送消息没有任何反应,试想一下,用nil调用方法怎么可能有反应。而解决野指针错误的方法就是将对象的指针变为空指针。
打开僵尸对象
把环境设置为MRC
错误的原因是,向一个已经被释放的实例对象发送了消息。
5、关于nil、Nil、NULL
1> nil是一个对象值(对象为空) 将对象等于nil。可以防止调用僵尸对象报错
2> Nil是一个类对象(类对象为空)
3> NULL是一个通用指针(泛型指针)
4> [NSNull null]是一个对象,用在不能使用nil的场合。
6、@property参数
1> 控制set方法的内存管理
retain : release旧值,retain新值(用于OC对象)
assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
copy : release旧值,copy新值(一般用于NSString,保证字符串的安全性)
2> 控制需不需生成set方法
readwrite :同时生成set方法和get方法(默认)
readonly :只会生成get方法
3> 多线程管理
atomic :性能低(默认)
nonatomic :性能高
4> 控制set方法和get方法的名称
setter : 设置set方法的名称,一定有个冒号:
getter : 设置get方法的名称
7、NSString在内存管理中的问题
NSString *str1 =@"abc";
NSString *str2 = [NSString stringWithFormat:@"aaa"];
NSString *str3 = [NSString stringWithString:@"abc"];
NSString *str4 = [[NSString alloc] initWithFormat:@"aaa"];
NSString *str5 = [[NSString alloc] initWithString:@"abc"];
NSString *str6 = [[NSString alloc] init];// 在栈区?为啥它的引用计数那么大?NSLog(@"str1 = %@ , %p , %lu",str1,str1,str1.retainCount);
NSLog(@"str2 = %@ , %p , %lu",str2,str2,str2.retainCount);
NSLog(@"str3 = %@ , %p , %lu",str3,str3,str3.retainCount);
NSLog(@"str4 = %@ , %p , %lu",str4,str4,str4.retainCount);
NSLog(@"str5 = %@ , %p , %lu",str5,str5,str4.retainCount);
NSLog(@"str6 = %@ , %p , %lu",str6,str6,str5.retainCount);
// 打印
2016-01-21 21:26:36.979 NSString内存管理问题[3269:255674] str1 = abc , 0x100004230 , 18446744073709551615
2016-01-21 21:26:36.980 NSString内存管理问题[3269:255674] str2 = aaa , 0x61616135 , 18446744073709551615
2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str3 = abc , 0x100004230 , 18446744073709551615
2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str4 = aaa , 0x61616135 , 18446744073709551615
2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str5 = abc , 0x100004230 , 18446744073709551615
2016-01-21 21:26:36.981 NSString内存管理问题[3269:255674] str6 = , 0x7fff7c51bd00 , 18446744073709551615
// 然后说在IOS项目下又不一样,我姑且又试了一试,确实是内存地址不一样了,但是引用计数是什么鬼
2016-01-21 21:30:42.632 NSString内存管理[3289:257683] str1 = abc , 0x106f4c050 , 18446744073709551615
2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str2 = aaa , 0xa000000006161613 , 18446744073709551615
2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str3 = abc , 0x106f4c050 , 18446744073709551615
2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str4 = aaa , 0xa000000006161613 , 18446744073709551615
2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str5 = abc , 0x106f4c050 , 18446744073709551615
2016-01-21 21:30:42.633 NSString内存管理[3289:257683] str6 = , 0x107279380 , 18446744073709551615
// 最后,我不死心,又试了一下
NSArray *array1 = [[NSArray alloc] init];
NSLog(@"array1 = %lu",array1.retainCount);
NSMutableArray *array2 = [[NSMutableArray alloc] init];
NSLog(@"array2 = %lu",array2.retainCount);
// 打印
2016-01-21 21:48:01.828 NSString内存管理问题[3447:267148] array1 = 2// 妈蛋 为什么是2
2016-01-21 21:48:01.828 NSString内存管理问题[3447:267148] array2 = 1
// 最后
看到最后,有这么一张图
总结一下吧,不要相信retainCount的值。(不要用它去做判断)
平常都在用ARC,也没注意到有这些问题,既然看到了,就权当了解一下。
事件处理
好了今天先总结这么多。明天继续,用一周时间来整理好基础知识,再总结一下自己在开发中如何采坑的。