成员变量、实例变量、属性

作者: YuWenHaiBo | 来源:发表于2016-06-20 22:04 被阅读960次
    • 成员变量和实例变量
      Objective-C 引入了“实例变量"的概念,但同时, 也经常出现 “成员变量”的声音。 到底什么是实例变量,什么是成员变量,二者的区别是什么呢?
      如果你之前接触过C++, Java对成员变量(member varialbe) ,肯定不陌生。 今天,你又看到了这个熟悉的叫法, 定会感到 Objective-C 没想象中的那么难。
      上图:

    图中的Member Variable declarations翻译过来就是成员变量的声明
    貌似 { } 中所声明的变量都为成员变量。 既然如此,实例变量又是什么意思呢?
    既然OC的表达方式是英文, 不妨从英文中查知原本的含义。

    类: Class (description/template for an object)
    实例: Instance (manifestation of a class)
    消息: Message (sent to object to make it act)
    方法: Method (code invoked by a Message)
    实例变量: Instance Variable (object-specific storage)
    超类/子类: Superclass/Subclass (Inheritance)
    协议:  Protocol (non-class-specific methods)
    

    从给出的英文说明,可以看出:实例(Instance)是针对 类(class)而言的。实例是指类的声明;由此推理,实例变量(Instance Variable) 是指由类声明的对象
    严格说来,上图中的 int count; 是一个成员变量。
    而 *NSString name; 是一个实例变量(NSString是一个类)。
    至于 id data 应该属于成员变量还是实例变量呢? 因为 id 是 OC特有的类型。从本质上讲, id 等同于 (void *)。 所以 id data 应属于 实例变量。
    说清实例变量和成员变量接下来我们说说属性。

    • 类Class中的属性property
      在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如:

      @interface MyViewController :UIViewController
      { 
          UIButton *myButton;
      }
      @property (nonatomic, retain) UIButton *myButton;
      @end
      

    在现在iOS版本中:苹果将默认编译器从GCC转换为LLVM(low level virtual machine),从此不再需要为属性声明实例变量了。如果LLVM发现一个没有匹配实例变量的属性,它将自动创建一个以下划线开头的实例变量。因此,在这个版本中,我们不再为输出口声明实例变量。

      例如:MyViewController.h文件
          @interface MyViewController :UIViewController
          @property (nonatomic, retain) UIButton *myButton;
          @end
    

    在MyViewController.m文件中,编译器也会自动的生成一个实例变量_myButton。那么在.m文件中可以直接的使用_myButton实例变量,也可以通过属性self.myButton.都是一样的。
      注意这里的self.myButton其实是调用的myButton属性的getter/setter方法。这与C++中点的使用是有区别的,C++中的点可以直接访问成员变量(也就是实例变量)。
      例如在oc中有如下代码

           @interface MyViewController :UIViewController
          { 
          NSString *name;
          }
          @end
    

    .m文件中,self.name 这样的表达式是错误的。xcode会提示你使用->,改成self->name就可以了。因为oc中点表达式是表示调用方法,而上面的代码中没有name这个方法。
      oc语法关于点表达式的说明:"点表达式(.)看起来与C语言中的结构体访问以及java语言汇总的对象访问有点类似,其实这是oc的设计人员有意为之。如果点表达式出现在等号 = 左边,该属性名称的setter方法将被调用。如果点表达式出现在右边,该属性名称的getter方法将被调用。"
      所以在oc中点表达式其实就是调用对象的setter和getter方法的一种快捷方式, 例如:dealie.blah = greeble 完全等价于 [dealie.blah setBlah:greeble];
      以前的用法,声明属性跟与之对应的实例变量:

       @interface MyViewController :UIViewControlle
      { 
      UIButton *myButton;
      }
      @property (nonatomic, retain) UIButton *myButton;
      @end
    

    这种方法基本上使用最多,现在大部分也是在使用,因为很多开源的代码都是这种方式。但是ios5更新之后,苹果是建议以以下的方式来使用:

     @interface MyViewController :UIViewController
     @property (nonatomic, retain) UIButton *myButton;
     @end
    

    因为编译器会自动为你生成以下划线开头的实例变量_myButton,不需要自己手动再去写实例变量。而且也不需要在.m文件中写@synthesize myButton,也会自动为你生成setter,getter方法。
    @synthesize的作用:
    (1)让编译器为你自动生成setter与getter方法。
    (2)可以指定与属性对应的实例变量,
    例如:
    @synthesize myButton = xxx;
    那么self.myButton其实是操作的实例变量xxx,而不是_myButton了。
    现在:如果.m文件中写了@synthesize myButton,那么生成的实例变量就是myButton;如果没写@synthesize myButton,那么生成的实例变量就是_myButton。所以跟以前的用法还是有点细微的区别。

    • 类别中的属性property
      类与类别中添加的属性要区分开来,因为类别中只能添加方法,不能添加实例变量。经常会在ios的代码中看到在类别中添加属性,这种情况下,是不会自动生成实例变量的。
      比如在:UINavigationController.h文件中会对UIViewController类进行扩展

      @interface UIViewController (UINavigationControllerItem)
      @property(nonatomic,readonly,retain) UINavigationItem *navigationItem;
      @property(nonatomic) BOOL hidesBottomBarWhenPushed;
      @property(nonatomic,readonly,retain) UINavigationController *navigationController;
      @end
      

    这里添加的属性,不会自动生成实例变量,这里添加的属性其实是添加的getter与setter方法。
      注意一点,匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)。
    参考博客:
    链接地址一

    相关文章

      网友评论

      本文标题:成员变量、实例变量、属性

      本文链接:https://www.haomeiwen.com/subject/bfowdttx.html