[Objective-C]第七天

 -------------------------------

     今日内容提要:

     1. 复习

     2. 自动释放池.

     3. 作业讲解.微博练习.

     4. ARC机制概述.

     5. 第一个ARC程序

     6. ARC机制下的单个对象的内存管理.

     7. ARC机制下的多个对象的内存管理.

     8. @property参数 strong与weak

     9. ARC下的循环引用问题.

     10.@property参数总结

     11.ARC与MRC兼容.

     12.MRC转换为ARC

     13.分类的基本使用

     14.非正式协议.

     15.延展.

 -----------------------------

复习:

  0. 在MRC的模式下,我们只需要管理OC对象. 其他的数据都不需要我们进行管理.

     决定OC对象什么时候被释放.

  1. MRC下的内存管理原理.

     每1个对象都有1个retainCount属性.叫做引用计数器.

     占据8个字节,类型是unsinged long

     引用计数器的作用:用来记录这个对象有多少个人正在使用.

     当我们创建1个对象,这个对象的引用计数器为1.

     如果有人使用这个对象,就让这个对象的引用计数器加1. 代表多1个人使用这个对象.

     如果这个人不再使用这个对象,就让这个对象的引用计数器减1.代表少1个人使用这个对象.

     当对象的引用计数器为0的时候.系统就会立即回收这个对象,并调用对象的dealloc方法.

     关闭ARC的方式.

     重点和难点:

     什么时候为对象的引用计数器+1

     什么时候为对象的引用计数器-1

  2. 操作引用计数器的方式.

     为对象发送retain消息. 对象的引用计数器就会加1. 这个消息的返回值是对象本身,

     为对象发送release消息,对象的引用计数器就会减1.

     为对象发送retainCount消息,就会返回对象的引用计数器的值.

     在对象的引用计数器为0的时候,对象就会被系统立即回收,并调用这个对象的dealloc方法.

     引用计数器的改变只能调用retain(++)、release(--),不能直接赋值.

  3. 在MRC下,重写dealloc方法的规范.

     必须要调用父类的dealloc方法,并且要放在最后调用. 别问为什么.

     为什么? 因为子类中有父类的属性.而父类属性的release是放在父类的dealloc方法之中的.

     为了能够释放所有的对象 必须要调用父类的dealloc方法.

                

[super dealloc];

  4. 内存管理的原则

     1). 有对象的创建,就必须要匹配1个release.

     2). 只有在多1个人使用的时候,才为对象发送retain消息,只有当少1个人使用的时候才为对象发送release消息.

     3). 谁retain 谁release

     4). retain的次数要和release的次数匹配.

     有始有终,有加就应该有减.

曾经让某个对象的引用计数器加1.就应该在不使用这个对象的时候让对象的引用计数器减1】.

  5. 野指针与僵尸对象.

     1). 概念

     野指针: 指针指向的对象已经被释放,这个指针就叫做野指针.

     僵尸对象:1个被释放的对象,就叫做僵尸对象.

    通过野指针去访问1个僵尸对象的时候.是有可能会出问题的.

    [对象的回收的本质]:

     是对象占用的空间系统可以分配给别的对象.  

     在未被分配给别的程序之前 其实啊这个对象还在的.数据也在的. 但是这块空间随时有可能分配给别的程序.

     在未被分配给别的对象之前 其实还是可以访问的

     一旦分配给别人就不能访问了.

     僵尸对象就不应该被允许访问 因为被释放了.

     开启僵尸对象检测.

     2). 如何避免使用僵尸对象.

         当指针为野指针的时候,将其赋值为nil.

     3). 无法让僵尸对象复活.

  6. 单个对象的内存泄露.

     1).什么叫做内存泄露?

        指对象没有被回收,该回收的时候而没有被回收,一直驻留在内存之中直到程序结束. 

     2).单个对象发生内存泄露的原因.

        -> 有对象的创建,没有匹配的release

        -> retain与release不匹配.

        -> 在不恰当的时候,指针赋值为nil

        -> 在方法中不当使用retain.

     3).如何做到单个对象被正确释放

        -> 有对象的创建就要有对象的release。

        -> 有多少个retain就要有多少个release。

        -> 不要轻易的为1个指针赋值为nil 除非指针是1个野指针.

        -> 在方法中不要轻易的为参数retain

  7. 多个对象的内存泄露.

        演示.人与车.出现的内存泄露.

     1). 当1个对象的属性是另外1个对象的适时候,如果对这个属性的set封装还是像我们基础班那样直接赋值.

         这样是会出问题.会出现野指针的问题.

  8. set方法的内存管理.

     在MRC的模式下,如果属性的类型是OC对象类型的,这个属性的setter方法应该如何写.

     1). 先retain传入的对象. 赋值给属性.在dealloc中release。

     2). 重新赋值1个对象的时候 旧对象无法释放.

         先release旧的对象,再retain新的对象.

     3). 当多次赋值同1个对象的时候.就会出现僵尸对象 。

  9. @property参数.

     1). @proerty的作用

         @property int age;

         a. 生成1个私有的,int类型的属性_age; 是声明在@implementation的大括弧之中.

         b. 生成getter、setter的声明.

         c. 生成getter、setter的实现,

            setter的实现: 将传递进来的值不做任何操作直接赋值给属性.

     2), @property可以带参数. 不同的参数有不同的效果.

         a,与多线程相关的.

            atomic: 默认的.

            nonatomic:

            选择nonatomic. 因为效率高.

         b. 和生成的set方法相关的参数.

            retain 生成的set方法就是标准的MRC内存管理代码. 不再是直接赋值了 

                   而是先判断新旧对象是否为同1个对象.如果不时 relase旧的 retain新的.

                   retain只是生成的set方法是标准的MRC内存管理代码.  不会自动的在dealloc中release 

                    所以,我们还要在dealloc方法中手动的relase属性指向的对象.

            assign: 默认值 生成的set方法中不做其他任何操作 直接赋值.

            如果属性的类型是OC对象类型的,那么使用retain

            如果属性的类型是非OC对象类型的 那么使用assign

         c. 和生成的属性 只读、读写有关的参数.

            readwrite: 默认值,getter setter同时生成.

            readonly: 只生成getter

         d. 修改生成getter setter方法的名字.

            一般情况下别改, 只在1个地方.

            当属性的类型是BOOL类型的时候 就更改getter的名字以is开头.

10. @class

      两个头文件相互包含的时候 如果两边都使用#import来包含 就会出错 就会死循环.

      其中1个头文件 不要使用#import指令 而是是@class 类名;

      @class Person;

      在.m文件中再去#import

  11. 循环retain

      当两个对象相互关联的时候.

      人对象中有1个车  

      车对象中有1个人. 

      如果这两个@property都使用retain 就会出现泄漏.

      解决方案:  1端retain 1端assign 使用assign的那1端不再需要在dealloc中release了.

02-自动释放池

  1. 自动释放池的原理.

     存入到自动释放池中的对象,在自动释放池被销毁的时候.会自动调用存储在该自动释放池中的所有对象的release方法.

     可以解决的问题:

     将创建的对象,存入到自动释放池之中. 就不再需要手动的relase这个对象了.

     因为池子销毁的时候 就会自动的调用池中所有的对象的relase。

     自动释放池的好处: 将创建的对象存储到自动释放池中,不需要再写release

  2. 如何创建自动释放池.

     @autoreleasepool

     {

     }

     这对大括弧代表这个自动释放池的范围.

  3. 如何将对象存储到自动释放池之中

     在自动释放池之中调用对象的autorelease方法.就会将这个对象存入到当前自动释放池之中.

     这个autorealse方法返回的是对象本身. 所以,我们可以这么写

@autoreleasepool
{
    Person *p1 = [[[Person alloc] init] autorelease];
}

     这个时候,当这个自动释放池执行完毕之后,就会立即为这个自动释放池中的对象发送1条release消息.

     目前为止,我们感受到得autorelase的好处:

     创建对象,调用对象的autorelase方法 将这个对象存入到当前的自动释放池之中.

     我们就不需要再去relase 因为自动释放池销毁的时候 就会自动的调用池中所有对象的relase

     [省略的是创建的对象的对应的那个release] 

  4. 使用注意

     1). 只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池之中.

         如果只是将对象的创建代码写在自动释放之中,而没有调用对象的autorelease方法.是不会将这个对象存储到这个自动释放池之中的.

     2). 对象的创建可以在自动释放池的外面,在自动释放池之中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池之中.

     3). 当自动释放池结束的时候.仅仅是对存储在自动释放池中的对象发送1条release消息 而不是销毁对象.

     4). 如果在自动释放池中,调用同1个对象的autorelease方法多次.就会将对象存储多次到自动释放池之中.

         在自动释放池结束的时候.会为对象发送多条release消息.那么这个是就会出现僵尸对象错误.

         所以,1个自动释放池之中,只autorelease1次,只将这个对象放1次, 否则就会出现野指针错误.

     5). 如果在自动释放池中,调用了存储到自动释放中的对象的release方法.

         在自动释放池结束的时候,还会再调用对象的release方法. 

         这个时候就有有可能会造成野指针操作.

        也可以调用存储在自动释放池中的对象的retain方法.

     6). 将对象存储到自动释放池,并不会使对象的引用计数器+1

          所以其好处就是:创建对象将对象存储在自动释放池,就不需要在写个release了.

     7).  自动释放池可以嵌套.

          调用对象的autorelease方法,会讲对象加入到当前自动释放池之中

          只有在当前自动释放池结束的时候才会像对象发送release消息.

 5. autorelease的规范.

     0). 创建对象,将对象存储到自动释放池之中. 就不需要再去手动的realse。

     1). 类方法的第1个规范:

         一般情况下,要求提供与自定义构造方法相同功能的类方法.这样可以快速的创建1个对象.

     2). 我们一般情况下,写1个类. 会为我们的类写1个同名的类方法,用来让外界调用类方法来快速的得到1个对象.

         规范:使用类方法创建的对象,要求这个对象在方法中就已经被autorelease过了.

         这样,我们只要在自动释放池中, 调用类方法来创建对象, 那么创建的对象就会被自动的加入到自动释放中.

         提供1个类方法来快速的得到1个对象.

         规范

         a. 这个类方法以类名开头. 如果没有参数就直接是类名 如果有参数就是 类名WithXX:

         b. 使用类方法得到的对象,要求这个对象就已经被autorelease过了.

+ (instancetype)person
{
    return [[[self alloc] init] autorelease];
}

         这样,我们直接调用类方法.就可以得到1个已经被autorelease过的对象.

         @autoreleasepool

         {

             Person *p1 = [Person person];

             //这个p1对象已经被autorelase过了.不需要再调用autorelase

             //这个p1对象就被存储到当前自动释放池之中.

         }//当自动释放池结束.就会为存储在其中的p1对象发送release消息.

 

 6. 实际上Apple的框架中的类也是遵守这个规范的.

    通过类方法创建的对象都是已经被autorelease过的了.

    所以,我们也要遵守这个规范. 类方法返回的对象也要被autorealse过.

    以后,我们凡事创建对象是调用类方法创建的对象 这个对象已经是被autorelease过的了.

03-微博练习

 在MRC

 一、微博类 (Microblog)

属性:

* 文字内容

 * 图片

 * 发表时间 (可以用字符串表示NSString)

 * 作者

 * 被转发的微博

 * 评论数

 * 转发数

 * 点赞数

//
//  Microblog.h
//

#import <Foundation/Foundation.h>
#import "User.h"

@interface Microblog : NSObject

@property (nonatomic,retain)NSString * content;
@property (nonatomic,retain)NSString * picURL;
@property (nonatomic,assign)CZdata  postTime;
@property (nonatomic,retain)User * user;
@property (nonatomic,retain)Microblog * microblog;
@property (nonatomic,assign)int review;
@property (nonatomic,assign)int forward;
@property (nonatomic,assign)int like;


@end
//
//  Microblog.m
//

#import "Microblog.h"

@implementation Microblog
-(void)dealloc{
    NSLog(@"微博被删除了");
    [_content release];
    [_picURL release];
    [_user release];
    [_microblog release];
    [super dealloc];
}
@end

 二、作者类 (User)

 * 名称

 * 生日

 * 账号

//
//  User.h
//

#import <Foundation/Foundation.h>
#import "Account.h"
@interface User : NSObject

@property (nonatomic,retain)NSString * nickname;
@property (nonatomic,assign)CZdata birthday;
@property (nonatomic,retain)Account * account;

@end
//
//  User.m
//

#import "User.h"

@implementation User

-(void)dealloc{
    NSLog(@"用户被注销了~");
    [_nickname release];
    [_account release];
    [super dealloc];
}
@end

 三、账号类 (Account)

 * 账号名称

 * 账号密码

 * 账号注册时间 

//
//  Account.h
//

#import <Foundation/Foundation.h>
typedef struct{
    int year;
    int month;
    int day;
}CZdata;

@interface Account : NSObject

@property (nonatomic,retain) NSString * accountId;
@property (nonatomic,retain) NSString * password;
@property (nonatomic,assign) CZdata regTime;

@end
//
//  Account.m
//

#import "Account.h"

@implementation Account

-(void)dealloc{
    NSLog(@"账户被封禁了~");
    [_accountId release];
    [_password release];
    [super dealloc];
}

-(void)setAccountId:(NSString *)accountId andPassword:(NSString *)password andRegTime:(CZdata)regTime{
    
    _accountId = accountId;
    _password = password;
    _regTime = regTime;
    NSLog(@"恭喜!【%@】注册成功!",_accountId);
}

@end
//
//  main.m
//

#import <Foundation/Foundation.h>
#import "Microblog.h"

int main(int argc, const char * argv[]) {

    @autoreleasepool {
        Account * reg1 = [[Account new]autorelease];
        reg1.accountId= @"wangdachui";
        reg1.password = @"123456+";
        reg1.regTime = (CZdata){2010,1,1};
        
        
        User * u1 = [[User new]autorelease];
        u1.nickname = @"王大锤";
        u1.birthday = (CZdata){1980,12,12};
        u1.account = reg1;
        
        
        Microblog * m1 = [[Microblog new]autorelease];
        
        m1.content =@"今天心情不错";
        m1.picURL = @"goodDay.png";
        m1.postTime =(CZdata){2010,8,8};
        m1.user = u1;
        m1.review = 100;
        m1.forward = 290;
        m1.like = 2000;
        
        Account * reg2 = [[Account new]autorelease];
        reg2.accountId= @"baike";
        reg2.password = @"123456";
        reg2.regTime = (CZdata){2010,1,1};
         
        
        User * u2 = [[User new]autorelease];
        u2.nickname = @"白客";
        u2.birthday = (CZdata){1980,12,12};
        u2.account = reg2;
        
        
        Microblog * m2 = [[Microblog new]autorelease];
        
        m2.content =@"今天心情确实不错";
        m2.picURL = @"goodDay.png";
        m2.postTime =(CZdata){2010,8,8};
        m2.microblog= m1;
        m2.user = u2;
        m2.review = 100;
        m2.forward = 290;
        m2.like = 2000;
 
    }

    return 0;
}

 ----结构体和类的区别-----

 1. 结构体只能封装属性,而类不仅可以封装属性还可以封装方法.

    如果1个封装数据既有属性也有行为,只能用类.

 2. 结构体变量分配在栈.OC对象分配在堆.

    栈的空间相对较小.但是存储在栈中的数据访问效率相对较高.

    堆的空间相对较大.但是存储在堆中的数据的访问效率相对较低.

    如果1个封装数据只有属性.如果用结构体就会分配在栈 效率就会高.

                        如果使用类型 对象就分配在堆 效率相对就会低.

    如果定义1个结构体,这个结构体中有很多个属性.那么这个时候结构体变量在栈中就会占据很大1块空间 反而会降低效率.

    什么时候使用结构体: 1). 封装数据只有属性 2) 属性较少. 3个以下.

    什么时候使用类: 1).封装数据既有属性也有行为. 2).只有属性 但是属性较多.

 3. 结构体赋值是 直接赋值的值. 而对象的指针 赋值的是对象的地址.

04-ARC机制概述

 1. 什么是ARC

    Automatic Reference Counting,自动引用计数. 即ARC. 

    顾名思义:系统自动的帮助我们去计算对象的引用计数器的值,

    可以说是WWDC2011和iOS5引入的最大的变革和最激动人心的变化. 

    ARC是新的LLVM3.0编译器的一项特性,使用ARC,可以说一举解决了广大iOS开着所憎恨的手动管理内存的麻烦.

    在程序中使用ARC非常简单,只需要像往常那样编写代码. 

    只不过永远不要写retain、release、autorelease 永远要手动的调用 dealloc 这三个关键字就好,这是ARC的最基本的原则.

    当ARC开启时, 编译器会自动的在合适的地方插入retain、release、autorelase代码. 

    编译器自动为对象做引用计数. 而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC).

    需要特别注意的是: ARC是编译器机制. 在编译器编译代码的时候,会在适时的位置加入retain、release和autorealse代码.

 2. ARC机制下,对象何时被释放

    本质: 对象的引用计数器为0的时候,自动释放.

    表象: 只要没有强指针指向这个对象,这个对象就会立即回收.

 3. 强指针与弱指针.

    强指针: 默认情况下,我们声明1个指针 这个指针就是1个强指针. 

           我们也可以使用__strong来显示的声明这是1个强指针.

           Person *p1; 这是1个强指针. 指针默认情况下都是1个强指针.

           __strong Person *p2; 这也是1个强指针.使用__strong来显示的声明强指针.

    弱指针: 使用__weak标识的指针就叫做弱指针.

    无论是强指针还是弱指针,都是指针,都可以用来存储地址,这1点没有任何区别 。

    都可以通过这个指针访问对象的成员.

    唯一的区别就是在ARC模式下.他们用来作为回收对象的基准. 

    如果1个对象没有任何强类型的指针指向这个对象的时候,对象就会被立即自动释放

 4. 确认程序是否开启ARC机制.

    1).默认情况下,Xcode开启ARC机制.

    2).ARC机制下,不允许调用retain、relase、retainCount、autorelease方法.

    3).在dealloc中 不允许[super dealloc];

 5.  演示第1个ARC案例

     int main(int argc, const char * argv[])

        {

            @autoreleasepool

            {

                Person *p1 = [Person new];//p1是1个强指针.

                //因为我们说过,每1个指针变量默认情况下都是1个强指针变量.

                NSLog(@"------");

            }//当执行到这里的时候.p1指针被回收,那么Person对象就没有任何

            //强指针指向它了. 对象就在这被回收.

            return 0;

     }

05-第一个ARC程序

 1. ARC下的单个对象的内存管理.

    在ARC的机制下: 当1个对象没有任何的强指针指向它的时候 这个对象就会被立即回收.

     1). 当指向对象的所有的强指针被回收的时候,对象就会被立即回收.

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        Person *p1 = [Person new];//p1是1个强指针.
        Person *p2 = p1;//p2也是个强指针.p1和p2都指向Person对象.
        //因为我们说过,每1个指针变量默认情况下都是1个强指针变量.
        NSLog(@"------");
    }//当执行到这里的时候.p1指针被回收,p2指针也被回收.那么Person对象就没有任何
     //强指针指向它了. 对象就在这被回收.
    return 0;
}

     2).将所有指向对象的强指针赋值为nil的时候.对象就会被立即回收.

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        Person *p1 = [Person new];//p1是1个强指针.
        //因为我们说过,每1个指针变量默认情况下都是1个强指针变量.
        p1 = nil;//当执行到这句话的时候.p1赋值为nil.
        //p1指针不再执行Person对象.
        //Person对象没有被任何的指针所指向,所以.Person对象在这里被释放.
        NSLog(@"------");
    }
    return 0;
}

     这两种情况就叫做没有任何强指针指向对象.

     1). 指向对象的所有强指针被回收掉

     2). 指向对象的所有的强指针赋值为nil

      

 2. 强指针与弱指针.

    1). 强指针与弱指针的声明.

     默认情况下,所有的指针都是强类型的,也就是说我们之前声明的指针变量都是强类类型的

     p1指针是强类型的,因为默认情况下指针都是强类型的.

     Person *p1 = [[Person alloc] init];

     不过我们可以使用__strong来显示的标识指针是强类型指针.

     __strong Person *p2 = [Person new];

     这个时候p2指针类型是强指针类型的.其实写不写__strong都是强类型的指针.

     指针类型也可以是弱指针类型.

     使用__weak标识指针的类型是弱类型指针.

     __weak Person *p3 = p2;

     这个时候,p3指针就是1个弱类型的指针. p3弱指针也指向p2指针指向的对象.

    在操作对象的时候,通过强指针或者弱指针都可以操作,没有任何区别.

    2). ARC模式下的对象回收标准

     ARC机制下释放1个对象的标准是: 没有任何强指针指向对象的时候,对象就会被释放.

     如果这个时候有弱指针指向,也会被释放.

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        //使用__strong来标识p1指针是强类型的,其实不写__strong也是强类型的.
         __strong Person *p1 = [[Person alloc] init];
        //使用__weak标识指针p2的类型是弱类型指针.
        __weak Person *p2 = p1;
        //这个时候,p2指针和p1指针都指向Person对象.
        //这个时候如果设置p1的值为nil
        p1 = nil;
        //这个时候Person对象只有被1个弱指针p2指向,没有任何强指针指向
        //所以Person对象在这里被回收.
    }
    return 0;
}

     3).最重要的1点:不能创建对象用1个弱指针存储这个对象的指针.

     这样的话,刚创建出来的对象,就没有任何强指针指向,创建出来就会被回收.

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        //创建1个对象,将这个对象的地址赋值给1个弱指针
        //后果就是创建出来的这个对象没有被任何强指针指向.
        //刚创建出来就会被释放.
        __weak Person *p1 = [[Person alloc] init];
    }
    return 0;
}

     4). 在ARC机制下. 当对象被回收的时候. 原来指向这个对象的弱指针会被自动设置为nil

        

06-ARC机制下的多个对象的内存管理

  1. ARC机制下的对象的回收的标准: 当没有任何强类型的指针指向对象的时候,这个对象就会被立即回收.

  2. 强类型指针 弱类型指针.

  3. 什么情况下叫做对象没有强指针向指向.

     1).  指向对象的强指针被回收.

     2).  指向对象的强指针被赋值为nil

  4. 在ARC的机制下,@property参数不能使用retain

     因为retain代表生成的setter方法是MRC的标准的内存管理代码.

     而我们在ARC的机制下 不需要这些代码.

     所以,在ARC机制下的setter方法 什么都不需要做.直接赋值就可以了.

  5. ARC机制下,我们关注的重点.

     当1个类的属性是1个OC对象的时候.这个属性应该声明为强类型的还是弱类型的.

     很明显,应该声明为1个强类型的.

     问题来了?

     如何控制@property生成的私有属性,是1个强类型的还是1个弱类型的呢?

     使用参数, strong和weak

     @property(nonatomic,strong)Car *car;

     代表生成的私有属性_car 是1个强类型的.

     @property(nonatomic,weak)Car *car;

     代表生成的私有属性_car 是1个弱类型的.

     如果不写,默认是strong.

  6. 使用建议.

     1). 在ARC机制下.如果属性的类型是OC对象类型的.绝大多数场景下使用strong

     2). 在ARC机制下.如果属性的类型不是OC对象类型的.使用assign

     3).  strong和weak都是应用在属性的类型是OC对象的时候. 属性的类型不是OC对象的时候就使用assign.

     --------

     在ARC机制下,将MRC下的retain换为strong

     @property(nonatomic,strong)Car *car;

     做的事情:

     1).  生成私有属性.并且这个私有属性是strong

     2).  生成getter setter方法的声明

     3).  生成getter setter方法的声明

          setter的实现:直接赋值.

07-ARC机制下的循环引用

 在ARC机制下.当两个对象相互引用的时候.如果两边都使用strong 那么就会先内存泄露.

 解决方案: 1端使用strong 1端使用weak

08-@property参数总结

  1. 开发程序分为ARC和MRC

  2. 与多线程相关的参数.

     atomic : 默认值 安全,但是效率低下.

     nonatomic: 不安全,但是效率高.

     无论在ARC还是在MRC都可以使用.

     使用建议: 无论是ARC还是MRC 都使用nonatomic

  3. retain

     只能用在MRC的模式下.代表生成的setter方法是标准的内存管理代码.

     当属性的类型是OC对象的时候.绝大多数情况下使用retain.

     只有在出现了循环引用的时候1边retain 1边assign

  4. assign:

     在ARC和MRC的模式下都可以使用assign.

     当属性的类型是非OC对象的时候 使用assign.

  5. strong:

     只能使用在ARC机制下.

     当属性的类型是OC对象类型的时候,绝大多数情况下使用strong  

     只有出现了循环引用的时候, 1端strong 1端weak

  6. weak:

     只能使用在ARC机制下.

    当属性的类型是OC对象的时候. 只有出现了循环引用的时候, 1端strong 1端weak

  7. readonly / readwrite 

     无论是ARC还是MRC 都可以使用.

  8. setter / getter

      无论在ARC下还是在MRC下都可以改.

 -----------------------------

 在ARC机制下.原来使用retain的用strong

 出现循环引用的时候. MRC: 1边retain 1边assign  ARC: 1边strong 1边weak

09-MRC与ARC的兼容

   1. 有可能会遇到的问题.

      程序使用的是ARC机制开发的,但是其中的某些类使用的是MRC.

   2. 使用命令.  -fno-objc-arc

10-MRC转换为ARC

   1. 可以将整个MRC程序,转换为ARC程序;(尽量不要用,没什么鸟用的功能。。。。。)

 

11-分类

 1. 分类.

     类别、类目、category

 2. 写1个学生类:类中有很多个方法.

     吃 喝 拉 撒 睡.... 基本行为

     学习、敲代码、写书.... 学习

     玩Dota 玩LOL 玩CF.... 玩

     爬山、跑步、踢足球..... 运动

     ......

     如果将这些方法都写在同1个类模块中.当然完全是可以的.

     如果全都写在一个模块中,就显的很臃肿. 后期难以维护和管理.

     默认情况下1个类独占1个模块.这个是将所有的成员都写在这1个模块中.就很难管理.

     我们的想法: 那就让1个类占多个模块.将功能相似的方法定义在同1个模块中.

               这样的好处: 方便维护和管理.

     如何将1个类分成多个模块呢?

  3. 分类:

     1). 顾名思义: 将1个类分为多个模块.

     2). 如何为1个类添加分类.

 

     3). 会生成1个.h 和1个.m的模块.

         a. 模块的文件名:  本类名+分类名.h     本类名+分类名.m

     4). 添加的分类也分为声明和实现.

         @interface 本类名 (分类名)

         @end

         代表不是新创建1个类.而是对已有的类添加1个分类. 小括弧中写上这个分类的名字.

         因为1个类可以添加多个分类 为了区分每1个分类.所以分类要取名字.

         @implementation Student (itcast)

         @end

         这是分类的实现.

  4. 分类的使用.

     1) 如果要访问分类中定义的成员,就要把分类的头文件引进来.

  5. 分类的作用: 将1个类分为多个模块.

 --------------------------------------------

 使用分类注意的几个地方:

   1. 分类只能增加方法,不能增加属性

   2. 在分类之中可以写@property 但是不会自动生成私有属性. 也不会自动生成getter setter的实现.

       只会生成getter setter的声明.

       所以,你就需要自己写getter 和 setter的声明. 也需要自己定义属性 这个属性就必须在本类中.

  3. 在分类的方法实现中不可以直接访问本类的真私有属性(定义在本类的@implementation之中)

       但是可以调用本类的getter setter来访问属性.

       本类的@property生成的私有属性,只可以在本类的实现中访问.

       分类中不能直接访问私有属性 真.

       分类可以使用 getter setter 来访问. 

   4. 分类中可以存在和本类同名方法的.

       当分类中有和本类中同名的方法的时候,优先调用分类的方法.哪怕没有引入分类的头文件.

       如果多个分类中有相同的方法,优先调用最后编译的分类.

 ------------------------------------

 什么时候需要使用分类.

 当1个类的方法很多很杂的时候. 当1个类很臃肿的时候.

 那么这个时候我们就可以使用分类. 将这个类分为多个模块.将功能相似的方法写在同1个模块之中.


14-非正式协议

  1. 分类的作用在于可以将我们写类分为多个模块.

     可以不可以为系统的类写1个分类呢?

     为系统自带的类写分类 这个就叫做非正式协议.

  2. 分类的第2个作用:

      为1个已经存在的类添加方法.

  3. NSString类都挺好的. 就是差了1个方法.

     统计字符串对象中有多少个阿拉伯数字.

 

  分类的作用

  1). 将臃肿的类分为多个模块 方便管理.

  2). 扩展1个类.

15-补充(GC与ARC)

  1. ARC机制垃圾回收机制的区别.

     GC: 程序在运行的期间,有1个东西叫做垃圾回收器.不断的扫描堆中的对象是否无人使用.

         Person *p1 = [Person new];

         p1 = nil;

     ARC: 不是运行时. 在编译的时候就在合适的地方插入retain......

          插入的代码足以让对象无人使用的时候 引用计数器为0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值