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父类名

实例变量  类似于结构体中的结构体成员,必须写在大括号内,而且大括号内只能写实例变量

NSString相当于c语言中的定义字符串char a[20]
NSInteger相当于C语言中得 int;

-(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文件中再将头文件导入即可.


1.通过作业题,讲了OC中的”继承”,通过多个类总结出来父类(通过相同的特点和行为),然后使用继承可以简化很多代码
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);

6.排序(升序)

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 降序 1

 NSComparisonResult 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可以方便的为系统添加方法 实现我们想要的但系统没有提供的操作


1.延展  也是扩充类的功能的 一种方式,只不过延展扩充的内容是私有的 ,是在.m文件中定义的
//延展既可以扩展方法也可以扩展实例变量,只不过都是私有的 ,外接无法直接访问
//延展是为源代码的类扩充内容(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];
    }
   
















0 0