OC完整总结
来源:互联网 发布:大逃杀新手知乎 编辑:程序博客网 时间:2024/06/06 08:29
面向过程的编程(procedure-oriented programming,POP:以事件为中心,关心完成事件的详细步骤,一步一步如何实现)
面向对象的编程(Object Oriented programming,OOP,以事物为中心,也就是参与事件的参与者,设计事物的功能,而完成事件只是所有功能中的一个小功能)
简单的说就像人吃饭,面向过程就是人怎么去吃饭(用筷子啊,清蒸啊,红烧啊等等),面向对象就是以人为基准(人能 吃喝拉撒睡等)以饭为基准(饭有 米饭面条海鲜各种不同做法等),人怎么去吃饭只是所有功能的一部分
类:具有相同特征和相同行为事物的抽象
类是一个抽象的概念生活中不具体
对象:是类的实例 也就是类的具体表现 生活中的万物都是对象
描述一个类: 通过特征(静态属性)行为(动态属性)
@是OC的标志
类的定义分为两部分,:
1:类的接口部分,提供外部访问的接口相当于使用说明书
2:类的实现部分详单与功能的实现
类的接口部分写在 .h 文件中
接口部分的定义:(1)以@interface开始 以 @end结束,只有把类的接口定义内容写在之间才有效
(2)Person 类名.
(3) : 号表示继承. 表示他有父类
(4)NSObject父类名
实例变量 类似于结构体中的结构体成员,必须写在大括号内,而且大括号内只能写实例变量
-(void)sayhi;//方法名 sayhi , - 号的意思是 由 对象调用的方法, + 号则表示是由类调用的方法.
类的实现部分 写在.m 文件中
类的实现部分:(1) 写在@implementation 和 @end之间才有效
@implmentation 后的Person是要实现的类(需要指定对哪一个类实现)
方法调用采用 消息发送机制[receiver(接收者,类 或 对象) message(消息,方法)]
如何区分是给类还是对象发送消息 [- 开头是给对象发送的, + 开头是给类发送的]
创建对象分两步:
1 . 开辟空间.alloc 方法加号方法
通过[person alloc] 在堆区开辟的空间才是真正的对象,只不过对于指针变量per存储的首地址,通过它才能访问对象,所以我没问你把指针变量per叫做对象(但真正的对象是堆区空间per本质是指针变量)
id 可以代表所有的对象类型 ,可以用对应类型的对象来接收
Person *per = [Person alloc];
2 . 初始化 init 放法完成初始化操作 减号方法,对象调用
per = [per init];
- (id)initWithName:(NSString*)_name price:(NSInteger)_pricecolor:(NSString *)_color;
由自己定义的初始化方法,给自己的每个实例变量赋初值[per sayhi]; 由对象调用方法.
1.实例变量的可见度:一共有三种
@public:公共的,在任何文件中都可以访问,(访问方式是通过对象+指向操作符 + 实例变量,例如:per->name)
@protected:受保护的,有一定的访问权限,只允许在本类文件以及子类文件中访问,其他文件不可以访问
@private:私有的,只允许在本类文件中访问,不可以在子类文件以及其他文件中访问
默认的可见度是:@protected
为什么不声明为@public?
(1).声明为:@public 实例变量,外部可以访问以及修改,会影响到内部的一个实现,暴漏实现细节
(2).违背oc面向对象的三大特性之一:封装.(封装的思想是隐藏内部的实现,提供外接访问的接口)
为什么不声明为@private?
(1).声明为:@private的实例变量,子类文件访问不到,所以子类文件还需要重新定义声明.
(2).违背了oc面向对象的特性之一:继承 (父类有的东西,子类也有,可访问)
2.设置器 setter方法 与访问器 getter方法 的运用
3.文件和类的关系:文件和类没有直接关系,文件可以存放多个类,只要类符合接口部分和实现部分的定义格式就可以.但一般情况下,一个文件就定义一个类.
4.self的使用:谁调用该方法,self就代表谁.
当方法是一个 - 号方法时,调用该方法的对象是谁,self就代表当前对象
当方法是一个 + 号方法时,调用该方法的类是谁,self就代表当前类
5. + 方法中不能使用实例变量,实例变量是依托于对象存在的,只有有了对象,实例变量才会有空间.
6.循环导入问题:当导入头文件时,相当于把里面东西都复制一份,而当使用这个类时,这个类还没定义,因此,不能识别.
解决方案:在.h文件中使用@class,将类声明为一个字符串,但是它不具备类中的内容,因此,需要在.m文件中再将头文件导入即可.
2.再使用继承的时候,子类继承父类会将父类中除了声明为@private的实例变量和私有的方法之外的其他全部内同都会被继承.如果子类中有和父类中同样的内容,全部删掉保留自己独有实例变量,不然会引起重复定义的错误,当然这是指实例变量(私有方法:就是在.m文件中实现了,但是没有在.h文件中声明的方法,这类方法不允许在外部访问,可以在本类中访问.)
3.在子类中,如果方法和父类相同了,不会出现错误,因为,继承的时候可以重写父类的方法,这个时候会出现三种情况:①保留父类对该方法的实现,不重写方法,这是上面遇到的情况;②按子类重写之后的方法来实现.(实现方式,重写该类方法,写自己的实现体,完全忽视父类的实现);③对于该类方法既有父类对该方法的实现,也有子类对该方法的实现,这儿用到一个重要的关键吃super
4.super的作用:用来调用父类对该初始化方法的实现.而self用来调用自己的方法
5.自定义初始化在实现的时候,本类中只对自己独有的实例变量赋值即可,然后父类中有的可以通过super调用实现简化
6.便利构造器:①作用是快速创建对象,内部封装了创建对象的过程;②格式:⑴ + 号方法 ⑵返回值类型为 id 类型 ⑶以类名+with开头,拼接上多个参数(便利构造器与标准创建对象相比便利不了多少,而且占内存,一般情况下不建议使用)
1.创建对象
两种方式:(1)便利构造器(+号方法)
(2) 初始化方法
(3)根据字符串初始化OC字
符串对象(已弃用)
2.求字符串长度
3.获取字符串中的某个字符
给定的字符下标超出范围,即下标越界时,程序会crash
问题产生的原因.NSCFString == NSString ,又是一个- 号方法,所以问题产生的原因是:让一个NSString类型的对象,调用characterAtIndex:方法时,给定的字符下标超出范围,即下标越界
解决方案将数组下标修改范围之内即可.
4.判断是否已指定字符串开头,或者以指
定的字符串开头
注它可以判断字符串的开头和结尾是
否是已指定的的
5.查找指定字符串的范围(可以找出已
知字符串中的某段字符串内容)
6.字符串的截取 有三种方式
(1)获取给定下标之后的子串,包含指
定下标对应的字符
(2)获取给定下标之前的字串,从下标
为0开始,但不包含指定下标对应的字符
(3)获取指定范围内的字符串.
7.字符串拼接(可以把指定的字符串拼
接到已知的字符串上)
8.替换字符串(可以把已知的字符串中
的一类字符串或者一段字符串替换成
指定的字符串)
9.字符串比较
10.字符串和数值类型转换(可以转换字
符串类型)
NSMutableString是NSString的子类,但前者是可变的后者不可变
对于可变字符串的增删改方法,都是在原字符串基础上进行修改,所以修改之后原字符串的内容发上改变,所以无需返回值
我们会在什么情况下用到数组呢 ,这是我们做题时要问的问题 数组存在的价值在于:
(1)存储多个元素(2)存数元素只能是对象,对象可以使不同类型的(3)数组是一个有序的集合.
(4)数组中的元素可以重复 而且重复的对象会成为数组元素
今天我们学了如下NSArray类中常用的几个方法.
1,创建对象
(1)使用便利构造器 arraywithobject 创建对象可以指定多个对象元素元素间用逗号间隔
nil作为数组元素存放的结束标志,遇到 nil 之后的元素都不会放进数组
NSArray *array = [NSArray arrayWithObjects:@"aa",@"bb",@"cc",@"dd", nil];
(2)使用初始化方法 减号方法
NSArray *array1 = [[NSArraalloc]initWithObjects:@"aa",@"bb",@"cc",@"dd",@"aa",@"bb",@"cc",@"dd", nil];
2 获取数组中的元素个数
NSUInteger count = [array count];
3. 根据索引值获取对象
(1)根据指定下标获取对应元素
NSString *str = [array objectAtIndex:1];
NSLog(@"str = %@",str);
(2)获取数组第一个元素
NSString *str1 = [array firstObject];若数组为空 则返回 nil
而objectAtIndex:0 则会造成'NSRangeException [__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array'' 崩溃 下标越界
NSLog(@"str1 = %@",str1);//若数组为空 则返回 nil
(3)获取数组最后元素
NSString *str2 = [array lastObject];
NSLog(@"str2 = %@",str2);
4,获取对象在数组中的索引值
NSUInteger count1 = [array indexOfObject:@"dd"];
5.判断是否包含某些对象
BOOL isExist = [array containsObject:@"dd"];
NSLog(@"isExist = %d",isExist);
NSArray *sortArr = [array1 sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"sortarr = %@",sortArr);
7.快速遍历(快速枚举)
for (NSString *str2 in array1) {
NSLog(@"%@",str2);
}
普通的for循环方法for (int i = 0; i < [array count]; i++) {
NSString *str2 = [array objectAtIndex:i];
NSLog(@"str2 = %@",str2);
}
可变数组类 NSMutableArray和可变字符串类 一样 在原数组操作 不需要返回值
1创建数组对象
NSMutableArray *arr1 = [[NSMutableArray alloc]initWithObjects:@"aa",@"bb",@"cc",@"dd", nil];
2 添加元素
[arr1 addObject:@"ff"];
NSLog(@"arr1 = %@",arr1);
3 插入元素
[arr1 insertObject:@"gg" atIndex:1];
NSLog(@"arr1 = %@",arr1);
4 删除元素
[arr1 removeObject:@"bb"];
NSLog(@"arr1 = %@",arr1);
5 替换元素
[arr1 replaceObjectAtIndex:3 withObject:@"ee"];
NSLog(@"arr1 = %@",arr1);
6交换指定位置的元素
[arr1 exchangeObjectAtIndex:2 withObjectAtIndex:3];
NSLog(@"arr1 = %@",arr1);
7 对原数组进行排序
[arr1 sortUsingSelector:@selector(compare:)];
NSLog(@"arr1 = %@",arr1);
8 遍历
for (NSString *a in arr1) {//如果数组中的对象类型不同,我们就是用对象的泛型 id 类型 可以代表所有对象类型
NSLog(@"a = %@",a);
}
(移除所有元素)
[arr1 removeAllObjects];
NSLog(@"arr1 = %@",arr1);
基本数据型 和数值对象 转换NSNumber *a1 = [NSNumber numberWithChar:a];将字符类型的 变量a 转换为数值对a1
char b1 = [a1 charValue ];将数值对象转换为字符类型
字典存在的价值:1.大容器,用来存储多个数据 2.用来存储的数据具有一一对应的关系,(使用key来标识value) 3.对于字典的一对键值对(key-value)叫做字典中的一个元素,也叫一个条目,只要使对象就可以,不限制类型 4.字典是无序的, 5.字典中的key是唯一的,一个key只能对应一个value ,一个value可以对应多个key
一.NSDictionary类的一些方法
1.创建字典对象
(1).便利构造器
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"zhiyuan",@"name",@20,@"shenggao",@26,@"age" ,nil];
NSLog(@"%@",dic);
(2).初始化方法
NSDictionary *dic1 = [[NSDictionary alloc] initWithObjectsAndKeys:@"zhiyuan",@"name",@20,@"shenggao",@26,@"age" , nil];
NSLog(@"%@",dic1);
2.求字典元素个数
NSUInteger count = [dic1 count];
NSLog(@"%lu",count);
3.获取所有的key
NSArray *keys = [dic allKeys];
NSLog(@"%@",keys);
4.根据key获取对应的value
NSString *value = [dic objectForKey:@"name"];
NSLog(@"%@",value);
NSNumber * number = [dic objectForKey:@"age"];
NSLog(@"%@",number);
5.字典快速遍历
//快速遍历:对于数组来说,遍历到的是数组中的每一个元素,对于字典来说,遍历得到的是字典的key,然后通过key获取value
for ( NSString *key in dic) {
//检索到key之后,通过objectForKey:获取key对应的value
NSLog(@"%@",[dic objectForKey:key]);
}
二. NSMutableDictionary 类的一些方法
对于可变字典来说,比不可变字典多了增加,删除,修改操作
1.创建对象
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"guang",@"gun",@"xiao",@"guan",@"shuai",@"gn", nil];
NSLog(@"%@",dic);
2.求字典的元素个数
NSLog(@"%lu",[dic count]);
3.删除元素
[dic removeObjectForKey:@"gun"];
NSLog(@"%@",dic);
[dic removeAllObjects];
NSLog(@"%@",dic);
4.添加元素
[dic setObject:@"xiaocui" forKey:@"gun"];
NSLog(@"%@",dic);
5.修改key对应的value
[dic setObject:@"chengjie" forKey:@"gun"];
NSLog(@"%@",dic);
//setObject:forKey:工作原理:先根据指定的key查找字典中是否存在相同的key.如果存在,则修改key对应的value,如果不存在,在字典中添加一个元素,key-value键值对.
三.NSSet 类的一些方法
1.创建集合对象
//便利构造器
NSSet *set1 = [NSSet setWithObjects:@"9",@"9",@"6",@"5", nil];
NSLog(@"%@",set1);
//初始化方法
NSSet *set2 = [[NSSet alloc] initWithObjects:@"1",@"2",@"6",@"5", nil];
NSLog(@"%@",set2);
2.获取元素个数
NSLog(@"%lu",[set1 count]);
3.获取集合中的某个元素
NSString *str =[set1 anyObject];
NSLog(@"%@",str);
NSString *str1 =[set1 anyObject];
NSLog(@"%@",str1);
NSString *str2 =[set1 anyObject];
NSLog(@"%@",str2);
NSString *str3 =[set1 anyObject];
NSLog(@"%@",str3);
4.判断集合中是否包含某个元素
BOOL isCon = [set1 containsObject:@"10"];
NSLog(@"%d",isCon);
}
四. NSMutableSet类的一些方法
//可变集合
NSMutableSet *set3 = [NSMutableSet setWithObjects:@"1",@"2",@"6",@"5", nil];
1.添加元素
[set3 addObject:@"9"];
NSLog(@"%@",set3);
2.移除元素
[set3 removeObject:@"2"];
NSLog(@"%@",set3);
int (^block)(int x, int y) = ^(int x, int y)
{
return x + y;
};
int (^)(int x, int y) block变量的类型
/block --block变量的名字
^(int x, int y)
{
return x + y; ---block变量的初值,block用来存储函数.给block变量赋值
}; 时赋的时整个函数的实现
当把函数的实现赋给block变量之后,block变量就可以当做函数名使用
当在block内部使用block外部定义的 局部变量 时,如果,变量没被__block修饰,则在block内部是readonly(只读的),不能对他修改,变量前必须要有__block修饰
__block的作用告诉编译器,编译时在block内部不要把外部变量当做常量使用,还是当做变量使用
如果在block中访问全局变量时,就不需要__block修饰.学习属性之前回忆一下之前学到的setter方法和getter方法:
(1)setter方法的作用:用来为单一的实例变量赋值(只能是一个实例变量,多了的叫做get方法)
(2)setter方法的写法标准: - 号方法, 无返回值, 名字以set开头+要设置的变量的实例变量名(首字母需大写):(setter方法有且只有一个参数)+参数的类型(和实例变量的类型相同)+参数名(和实例变量名相同)
(3)getter方法的作用:用来获取单一实例变量的值.
(4)getter方法的写法标准: - 号方法, 有返回值(返回值类型和实例变量类型相同) 方法名直接和实例变量名相同 无参数
当实例变量较多的时候,用setter方法和getter方法会很不方便,代码量也加大,所以就有了属性的出现.属性是OC2.0之后出来的新的语法,用来替代setter和getter方法,使用属性可以快速创建setter和getter方法的声明,以及setter和getter方法的实现.此外,属性还添加了对实例变量操作的安全处理.
(1)属性的写法标准: @property(用来定义属性) 属性的类型(和实例变量的类型相同) 属性名(和实例变量名相同)
(2)注意:@property 知识自动声明setter和getter方法的声明
属性的三大特性:
(1)第一大特性:读写特性
readonly 告诉编译器,属性在自动生成方法时,只会生成getter方法,不会生成setter方法
readwrite 告诉编译器,属性在自动生成方法时,既要生成setter方法,也要生成getter方法,为系统默认的读写特性.
setter = aa; 告诉编译器,当自动生成setter方法时,setter方法的方法名为指定的名字aa,而不采用默认的
getter = bb; 告诉编译器,当自动生成getter方法时,getter方法的方法名为指定的名字bb,而不是采用默认的
(2)第二大特性:原子性特性
atomic : 原子特性,保证线程安全,内部做了安全处理(枷锁与解锁).为系统默认的原子特性.
nonatomic : 非原子性,不保证线程的安全,因为对于setter和getter方法的使用,比较频繁,在一段时间内可能要多次访问,所以使用atomic会非常消耗系统的资源,降低程序的执行效率,使用nonatomic虽然不能保证线程的安全,但是一般情况下得使用都是安全的,所以对于原子特性,使用nonatomic
(3)第三大特性:语义特性
assign : 直接赋值,针对于基本数据类型使用,也可以针对对象类型使用,为系统默认的语义特性
copy : 针对对象类型使用,并且要服从NSCopying协议的对象才可以,会复制出一个新的对象,拥有新的对象所有权(引用计数+1)(暂时理解到这里)
retain : 针对对象类型使用,会造成对象的引用计数+1.
属性的实现:
(1)写法标准:@synthesize 属性名 = 实例变量(指定的setter和getter方法内部所要操作的实例变量)
(2)如果标准写法中指定的实例变量没有定义,系统会自动生成指定的实例变量,但是生成的实例变量是私有的,子类不能直接访问,如果实例变量想让子类访问,那么在.h文件中必须定义实例变量.
(3)如果未指定setter和getter内部所要访问的实例变量时,系统会自动生成一个和属性名一样的实例变量.
(4)对于setter和getter方法,如果我们实现了,系统就不会再自动生成
(5)如果在.m文件中未通过@synthesize对属性进行合成,系统会自动合成,只不过此时系统默认的setter和getter方法内部所操作的实例变量是 _属性名
(6)如果将@synthesize省略,我们自己实现setter和getter方法时,系统就不会生成对应的setter和getter方法,以及实例变量.
(7)常用的是只在.h文件中声明属性,其他的系统自动生生成.
点语法,是一种快速访问setter和getter方法的方式(类似于之前的结构体变量访问结构体成员)
写法标准:对象名.属性名 -----如果放在等号的左边,就是调用setter方法,其他情况都是调用getter方法
声明属性时默认生成对应的setter和getter方法,所以属性和setter及getter方法都有关联.
今天我们学了 NSDate 方法 通过NSDate方法创建的对象 永远是 零时区的时间创建日期对象
当前时间创建NSDate
NSDate *myDate = [NSDate date];
获区两个日期的的时间间隔 时间间隔是以秒为单位
NSTimeInterval 是相当于 double
NSTimeInterval TimeInterval = [tomorrow timeIntervalSinceDate:yesterday];
NSLog(@"%f",TimeInterval/60/60/24);//原理是前面的时间 - 后面的时间 也可能出现负数
两个日期的比较 结果是枚举类型 升序 -1 相等 0 降序 1NSComparisonResult compare =[tomorrow compare:yesterday];
(类型1)类型2 强制类型转换可以将类型2转换为 类型1;
日期和字符串之间可以相互转换如:将日期格式串转化为 NSDate对像
NSString *s = [NSString stringWithFormat:@"2014年05月01日 10点23分18秒"];
创建日期格式串对象对象
NSDateFormatter *form =[[NSDateFormatter alloc]init];
设置日期格式(一定要和字符串中的日期格式保持一致)
form setDateFormat:@"yyyy年MM月dd日 HH点mm分ss秒"];
NSDate *day = [form dateFromString:s];
HH表示24小时制 hh表示12小时制
MM表示月份 mm表示分钟
dd 表示当月天数 DD表示处于本年第几天
ss表示秒数
如果年份为两个y 只显示年份的后两位 若果给其他个数的y 都显示完整年份
如果MM 给两位 月份为一位时补0
我们又学了 分类(category),可以拓展类的方法 但不能添加实例变量,为原有的类扩充方法 就会成为原类的一部分. 分类也分为 .h接口部分 以及.m实现部分. .h文件写方法的声明 .m写方法的实现
//分类定义格式 以@interface开始+扩展类名(分类名)以@end结束
例如 @interface NSString (Sort)(中间定义方法)
@end
实现写在 .m 中 通过category可以方便的为系统添加方法 实现我们想要的但系统没有提供的操作
//延展既可以扩展方法也可以扩展实例变量,只不过都是私有的 ,外接无法直接访问
//延展是为源代码的类扩充内容(Extension)
/*@interface Person ()
{
NSString *_aa;
NSString *_bb;//延展中添加私有的实例变量
}
- (void) sayHi;
- (void) sayAfternoon;
- (void) sayEvening;
@end
2.
协议 就相当于任务清单,规定所要做的操作,(只有一系列方法的声明),谁服从该协议,谁就是实现协议中的方法,(完成任务清单中的任务) 所以协议中有.h文件,没有.m文件
@protocol TeachingProtocol <NSObject>
- (void)teachKVC; //讲kvc
- (void)teachMemeory; //讲内存
@end
//<>表示服从协议,服从的协议写在<>之内
//@interface Person : NSObject <TeachingProtocol>
@end
//协议要让类来服从,服从协议后,要实现协议中的方法
3.协议名命名规范: 服从协议的类+delegate
代理的语义特性为:assign
//@property (nonatomic,assign) id <WomenDelegate> delegate; //丈夫
1.内存管理的基本原则:
如果对一个对象进行alloc ,retain ,copy 之后,你就拥有了该对象的所有权,你就必须对它进行release或者autorelease
2.内存管理常用的计数方法:
Manual Reference Count(MRC),人工引用计数
Auto Reference Count(ARC),自动引用计数
3.People *per1 = [[People alloc] init]; //0 - 1 alloc 开辟内存空间,并且将对象的引用计数由0变1.
NSLog(@"%ld",[per1 retainCount]);retainCount 用来获取当前对象的引用计数
People *per2 = [per1 retain];//1-2 retain 将对象的引用计数加1
[per2 retain];//2-3
[per2 release];//3-2 release将对象的引用计数(立即)-1
[per2 release];//2-1
[per2 release];//1-0
在次,如果你在[per2 release];一次,就会出现过度释放问题.下面给出原因,解决方案.
现象:当写完和内存引用计数-1有关的操作后,程序立即crash
原因:空间被系统回收之后,不能在做和引用计数-1有关的操作,否则立即crash
解决方案:删除
同时,在这里还会存在另一个问题:野指针现象
现象:可能会崩溃,也可能不会崩溃,写到某一行代码时突然崩溃,(没有写任何和引用计数相关的代码)
产生原因:该对象的空间已经被系统回收,不能访问没有所有权的对象
解决方案:空间被系统回收之后,禁止访问
4.autorelease
(1) autorelease 会将声明为autorelease的对象放入离它最近的自动释放池中,当自动释放池销毁时,会向池中的每一个对象发送一个release消息
(2) autorelease 使用方式有两种:
1). NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
People *per = [[People alloc] init];//引用计数0 -1
NSLog(@"%ld",[per retainCount]);
[per autorelease];//1 -0
[pool release]; (不经常用)
2).@autoreleasepool {
People *per = [[People alloc] init];//引用计数0 -1
[per autorelease];//1 -0
}
下面给出两道练习题:
1.@autoreleasepool {
for (long i = 0; i < 10; i ++) {
People *per = [[People alloc] init];
[per autorelease];
}
}
在这道题中,存在内存泄露问题,只开辟空间,延缓释放,从而导致内存泄露问题.解决方案如下:
@autoreleasepool {
for (long i = 0; i < 10; i ++) {
@autoreleasepool {
People *per = [[People alloc] init];
[per autorelease];
}
}
}
2.
@autoreleasepool {
NSString *per =[[NSString alloc] init];
[per retain];
[per retain];
per = @"aa";
[per release];
[per release];
[per release];
在这道题中,由"aa"在常量区,per = "aa" 是指针变量重指向,从而导致两个问题:1.内存泄露 2.管理常量区的空间
解决方案:去掉per ="aa",常量区的空间是由系统管理的
}
1.setter 以及getter方法,内部是对实例变量赋值以及实例变量取值操作,所以方法内部操作实例变量
/*
- (void) setTea:(Teacher *)tea
{
//判断原有对象和新对象是否是同一个,如果是同一个,就没必要重新赋值,否则,会先release,之后空间被系统回收,此时在retain就成为野指针问题
if (_tea != tea) {
[_tea release];//释放保有的之前对象的所有权 解决内存泄露问题
//让实例变量_tea 保有新的对象的所有权
_tea = [tea retain];//不能self.tea = tea; self.tea 调用set方法,这样会造成死循环 解决野指针问题
}
}*/
2.语义特性声明为copy,setter方法内部实现
- (void) setTea1:(Teacher *)tea1
{
if (_tea1 != tea1) {
[_tea1 release];
//如果想对一个对象进行copy操作,对象的类必须服从一个NSCopying协议,并且实现协议中的方法
_tea1 = [tea1 copy];
}
}
在类的.m文件中实现copyWithZone
- (id)copyWithZone:(NSZone *)zone
{
Teacher *newTea = [[Teacher allocWithZone:zone] init];
newTea.name = self.name;
newTea.gender = self.gender;
return newTea;
}
3.注意事项
- (id) initWithName:(NSString *)name gender:(NSString *)gender
{
self = [super init];
if (self ) {
// _name = name; 用_name=name 就是简单赋值操作,没有对其引用计数+1操作,而self.name = name 在内部给其引用计数+1操作,因此,在最后要对其release操作
self.name = name;
self.gender = gender;
}
return self;
}
4.遍历构造器内存管理
.m中内部实现
+(id) teacherWithName:(NSString *)name gender:(NSString *)gender
{
Teacher *tea= [[Teacher alloc] initWithName:name gender:gender];
return [tea autorelease];
}
Teacher *tea = [Teacher teacherWithName:@"frank" gender:@"girl"];
NSLog(@"%lu",[tea retainCount]); 3.3.3.d3. 3. }
5.collection 的内存管理
Teacher *tea1 = [[Teacher alloc] initWithName:@"xiao" gender:@"nan"]; // 0-1
Teacher *tea2 = [[Teacher alloc] initWithName:@"guang" gender:@"xia"];// 0 - 1
Teacher *tea3 = [[Teacher alloc] initWithName:@"jian" gender:@"man"];// 0 - 1
NSMutableArray *arr = [[NSMutableArray alloc ]initWithObjects:tea1,tea2, nil];
//当把一个对象放入集合(数组,字典,集合)中时,会将对象的引用计数 +1 ,因为内部做了 retain操作
//当collection(数组,字典,集合),空间被回收时,他们会向容器中的每一个元素都发送一个release消息(对应添加元素时的retain操作)
//当从collection(数组,字典,集合)中移除一个元素时,会release该对象,引用计数 -1
NSLog(@"%lu",[tea1 retainCount]);
[tea1 release];
[tea2 release];
[arr removeObjectAtIndex:0];
[arr release];
}
- OC完整总结
- 黑马程序员——对OC面向对象的完整总结
- OC 总结
- OC 总结
- OC总结
- OC总结
- OC总结
- OC总结
- OC总结
- OC-总结
- OC总结
- OC总结
- oc总结
- OC总结
- OC-总结
- OC总结
- OC 总结
- OC总结
- 一个反射方法响应web平台所有ajax数据请求,让web开发速度提高一倍
- 欧拉函数
- 索引
- Android NDK几点回调方式(device id & signature)
- zookeeper安装
- OC完整总结
- 电子设计硬件,软件,信号方向介绍
- 黑马程序员03——基础2
- 【原创翻译】Game Engine Architecture(游戏引擎架构)第一章导论
- Spring
- 外网访问用azure虚拟机搭建的网站
- POJ3104:Drying(二分)
- 对Linux新手非常有用的20个命令
- android开发框架简介