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)

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

    【写在结尾:】

    『想起一首席慕容的诗:

    一棵开花的树
    
    如何让你遇见我
    在我最美丽的时刻
    	
    为这
    我已在佛前求了五百年
    求佛让我们结一段尘缘
    佛於是把我化做一棵树
    长在你必经的路旁
    	
    阳光下
    慎重地开满了花
    朵朵都是我前世的盼望
    	
    当你走近
    请你细听
    那颤抖的叶
    是我等待的热情
    	
    而当你终於无视地走过
    在你身後落了一地的
    朋友啊
    那不是花瓣
    那是我凋零的心』
    ☂业精于勤,荒于嬉;行成于思,毁于随。☂
  • 相关阅读:
    IOS-JSON数据解析
    IOS-APP发布资料收集
    IOS-webService
    ASP.NET MVC学习之路:模板页
    io流
    线程
    事件监听
    java基础面试题
    递归调用
    三目运算: x?y:z
  • 原文地址:https://www.cnblogs.com/wang-biao/p/5663197.html
Copyright © 2011-2022 走看看