zoukankan      html  css  js  c++  java
  • OC-@property、self及类的本质

    让代码书写更加简便

    --1-- 设置器和访问器
    1.1 setter
    1.2 getter
    --2-- 类的本质
    2.1 类类型的对象
    2.2 类的本质
    2.3 如何获取类对象
    2.4 类对象的使用
    2.5 类对象的存储
    --3-- SEL类型
    3.1 SEL
    --4-- @property关键字
    4.1 基本概念
    4.2 @property用法
    4.3 @property使用注意事项
    --5-- @synthesize关键字
    5.1 @synthesize用法
    5.2 @synthesize使用注意
    5.3 @synthesize指定实例变量赋值
    --6-- self关键字
    6.1 介绍
    6.2 在对象方法中使用self
    6.3 用在类方法中使用self
    -------------------------------------

    【写在开头】

    『在面向对象的编程中,封装是其一个重要的特性。封装将一个可供外部使用的接口暴露出来,隐藏了复杂的代码逻辑实现。

    不可被外部任意存储是面向对象设计的本质,降低了数据被无用的可能性。

    外部就可以通过设置器setter和访问器getter来对对象的属性进行设置和访问,而不是直接访问对象的属性(->)

    在开发过程中,考虑到安全性要求,一般不再成员变量名前面使用@public@protected等关键字修饰,而是使用Set方法来为对象提供成员变量的值,在set方法的内部也可以对一些不合理的赋值进行筛选过滤。

    --1-- 设置器和访问器

    1.1 setter

    setter方法(设置器):在set方法的内部可以对一些不合理的数据过滤筛选。set方法作用:为提供一个设置成员变量值的方法。

    命名规范:

    1)方法名必须以set开头

    2)set后面跟上成员变量的名称,首字母大写

    3)返回值一定是void

    4)一定要接受一个参数,而且参数类型需要和成员变量的类型一致

    5)形参名不能和变量名一样(成员变量名以_线开头,苹果官方推荐成员变量名前加_以示区分)

    好处:

      1)不让数据暴露在外,保证了数据的安全性

      2)对设置的数据进行过滤

    {
        //成员属性
        NSString *_name;
        int _age;
    }

    setter

    //setter
    - (void)setName:(NSString *)name;
    - (void)setAage:(int)age;

    1.2 getter

    作用:为调用者返回对象内部的成员变量

    命名规范:

    1)一定有返回值,返回值的类型和成员变量的类型一致

    2)方法名和去掉下划线的成员变量名一样(此处与Java等语言不一样)

    3)不需要接收任何参数 

    //getter
    - (NSString *)name;
    - (int)age;

    --2-- 类的本质

    2.1 类类型的对象

    类的本质其实也是对象,只不过是class类型的对象,也叫做类对象

    2.2 类对象

    类对象

    * 类对象在程序运行时一直存在

    * 类对象是一种数据结构,存储类的基本信息:类大小,类名,类的版本以及消息与函数的映射表等

    * 类对象所保存的信息是在程序编译时确定,在第一次使用该类的时候被加载到内存中

    * 类对象代表类,class代表类对象,类方法属于类对象

    * 如果消息的接收者是类名,则类名代表类对象

    * 运行时,所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象

    * 从类对象里可以知道父类的信息、可以响应的方法等

    * 类对象只能使用类方法,不能使用实例方法

    2.3 如何获取类对象

    1)通过实例对象获取

        Person *person = [[Person alloc] init]; //创建对象
            
        //通过实例对象获取类对象Dog
        Class c1 = [person class]; //Class类型的是一个结构体指针
        Class c2 = [person class];
            
        NSLog(@"c1->%p", c1); //0x1000011d8
        NSLog(@"c2->%p", c2); //0x1000011d8

    2)通过类名获取(类名其实就是类对象)

        //通过类名获取类对象
        Class c3 = [Person class];
        
        NSLog(@"c3->%p", c3); //0x1000011d8

    发现通过类名和实例获取对象,所获得的对象是同一个

    实际上,都是获得了类对象Person class

    2.4 类对象的使用

    1)用类对象创建对象

    两个测试方法:

    //对象方法
    - (void)test;
    
    //类方法
    + (void)test;

    使用

        //用类对象来创建对象
        Person *person2 = [[c1 alloc] init];
        [person2 test]; //调用对象方法的test -test

     2)用类对象来调用类方法

        //用类对象来调用类方法
        [c1 test]; //调用类方法 +test

    2.5 类对象的存储

    isa指针

    • 每一个对象都包含一个isa指针.这个指针指向当前对象所属的类。
    • [p eat];表示给p所指向的对象发送一条eat消息,调用对象的eat方法,此时对象会顺着内部的isa指针找到存 储于类中的方法,执行。
    • isa是对象中的隐藏指针,指向创建这个对象的类。
    • 通过isa指针我们可以在运行的时候知道当前对象是属于那个Class(类)的。

    --3-- SEL类型

    3.1 SEL

    SEL:全称selector表示方法的存储位置

    方法调用的原理:其实每个类加载到内存中对象的方法都会封装成一系列的SEL列表,SEL会保存着这个方法的信息(当然包括方法的内存地址),当要调用该方法的时候,对象会通过isa指针找到内存中对应的方法的内存地址然后再调用该方法,在找到该方法之后该类对象会把该SEL放入缓存中,以便第二次寻找的时候提高效率

     

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

    [p test]; 

    寻找方法的过程

    1)首先把test这个方法名包装成SEL类型的数据

    2)根据SEL数据找到对应的方法地址

    3)根据方法地址调用相应的方法

    4注意:在这个操作过程中有缓存,第一次找的时候是一个一个的找,非常耗性能,之后再用到的时候就直接使用了

    --4-- @property关键字

    4.1 基本概念

    @property是编译器的指令。(编译器指令是由编译器完成的)

    好处是免去我们手工书写成员属性getter和setter方法繁琐的代码。

     

    4.2 @property用法

    格式:

      @property  类型名  方法名

     如:

      @property  int  age;

    相当于完成了age属性的set和get方法的声明和实现

     - (void)setAge:(int)age;

     - (void)age;

    注意:

    1、在Xcode4.4之前,用于帮我们实现get/set方法的声明

    2、在Xcode4.4之后,有增强功能,连实现也自动完成了

    Person.h->

    /*
      省略了方法的声明
      相当于是替换了下面的这两句声明
      - (void)setAge:(int)age;
      - (int)age;
     
     同时,还自动生成了对应的成员属性 _age,但是这个属性是私有的,外部只能通过setter/getter访问
      */
    @property int age;

    Person类中没有自定义 _age属性,但是@property自动生成了该属性:

    @implementation Person
    //对象方法
    - (void)test{
        NSLog(@"-TEST");
        self->_age = 3; //在这里可以看到,@property生成了一个_age属性
    }
    
    //类方法
    + (void)test{
        NSLog(@"+TEST");
    }
    @end

    调用:

    Person *person = [[Person alloc] init]; //创建对象
            
    //此处 _age属性由@property生成
    person.age = 3; //设置成员属性
    NSLog(@"person.age->%d", person.age); //3

    4.3 @property使用注意事项

    在老式的代码中

    @property只能写在@interface ...@end之间

    @property用来自动生成成员变量get/set方法的声明(Xcode4.4之前)

    告诉@property要生成的get/set方法声明的成员变量类型是声明

    告诉@property要生成的get/set方法是哪个属性的,属性名去掉下划线

    --5-- @synthesize关键字

    5.1 @synthesize用法

    @synthesize age;

    写在.m文件中,表示对生成.h中变量age的get和set方法的实现

    格式:

      @synthesize  方法名

     注意:

    如果使用@synthesize则变量名要先在.h文件中声明

    .h

    @property int age;

    .m

    @synthesize age;

    展开形式如下:

    @synthesize age; 
    //展开
    - (void)setAge:(int)age{
        self->age = age; //注意这里不是对Person原来的成员变量_age赋值,而是生成了一个变量age,然后对其进行赋值
    //(如果这里写self,那么这个变量age也就相当于是个成员变量了)
     
        //所以使用@synthesize时,下面只打印了age和name的值,没有对_age和_name进行操作
        //NSLog(@"age = %d, name = %@", age, name);
        //NSLog(@"_age = %d, _name = %@", _age, _name);
     }

    5.2 @synthesize使用注意

    Xcode4.4之前@property和@synthesize搭配使用,用于简化set和get方法的定义和实现

    5.3 @synthesize指定实例变量赋值

    声明

    @property  int  a;   

    实现

    @sythesize  a  =  _b;   //表示用a的get和set方法,修改属性b的值

    相当于下面的代码:

       - (void) setA:(int)a{

      _b = a;

      }

       - (int)a{

      reurn _b;

      }

    @interface Person : NSObject
    
    @property NSString *name;
    //如果两个实例变量的类型一致,如:age和weight,@property可以用逗号隔开变量,在一行上定义
    @property int age, weight; 
    
    //测试方法
    - (void)test;
    @end
    
    
    @implementation Person
    
    //用age的getter和setter方法,修改属性_age的值
    @synthesize age = _age, name = _name, weight = _weight;
    @end

    --6-- self关键字

    6.1 介绍

    OC语言中的self,就相当于C++、Java中的this指针。

    学会使用self,首先要搞清楚属性这一概念。

    以及理解getter(访问器)和setter(设置器)方法,它到底有什么用?

    设置器与访问器,提供外界操作 类内部属性的一个通道。

     

    假如没有这个方法,外界怎么操作类的内部属性。

    假如不提供这两个方法,那么这个属性的值,就不能为外界所改变。

    因为类的属性,默认是@protect(受保护类型)。

    self的应用场景

    1)用在类方法中

    2)用在对象方法中

    3)访问成员变量

    4)self在OC的内存管理特殊使用

    6.2 在对象方法中使用self

    //学生学习对象方法
    - (void)study{
        
        //此时self指代学生对象
        NSLog(@"- self->%p", self); //0x1002001b0
    }

    6.3 用在类方法中使用self

    //学生信息类方法
    + (void)info{
        
        //此时self指代学生类
        NSLog(@"+ self->%p", self); //0x1000013d0
    }

    查看:

        @autoreleasepool {
            
            Student *stu = [[Student alloc] init];
            
            //学生对象地址
            NSLog(@"stu->%p", stu); //0x1002001b0
            
            //学生类地址
            NSLog(@"Student-%p", [Student class]); //0x1000013d0
            
            //发送study和info消息
            [Student info]; //0x1000013d0
            [stu study]; //0x1002001b0
        }

    输出-->

    综上总结:

    self要指代谁?具体是要看self写在哪个方法中,

    如果self写在对象方法中,则指代的就是当前方法的对象([类 new])

    如果self写在类方法中,那么它指代的就是当前的类对象(类 class)

    注意这里类对象和对象是两个概念

    【写在结尾:】

    『想起一首席慕容的诗:

    一棵开花的树
    
    如何让你遇见我
    在我最美丽的时刻
    	
    为这
    我已在佛前求了五百年
    求佛让我们结一段尘缘
    佛於是把我化做一棵树
    长在你必经的路旁
    	
    阳光下
    慎重地开满了花
    朵朵都是我前世的盼望
    	
    当你走近
    请你细听
    那颤抖的叶
    是我等待的热情
    	
    而当你终於无视地走过
    在你身後落了一地的
    朋友啊
    那不是花瓣
    那是我凋零的心』
    ☂业精于勤,荒于嬉;行成于思,毁于随。☂
  • 相关阅读:
    希腊字母写法
    The ASP.NET MVC request processing line
    lambda aggregation
    UVA 10763 Foreign Exchange
    UVA 10624 Super Number
    UVA 10041 Vito's Family
    UVA 10340 All in All
    UVA 10026 Shoemaker's Problem
    HDU 3683 Gomoku
    UVA 11210 Chinese Mahjong
  • 原文地址:https://www.cnblogs.com/wang-biao/p/5663197.html
Copyright © 2011-2022 走看看