实例变量和属性

实例变量和属性

声明

Person 文件中

@interface Person : NSObject {

    NSString *_name; //实例变量

}

    @property(copy) NSString *firstName; //属性

    @property(copy) NSString *lastName;

@end 

_name 是实例变量,实例变量是类私有的变量,其他类对象无法直接访问;

写在头文件中的 firstName是属性,public,其他类对象可以直接访问;写在m文件中的属性是private,其他类对象无法直接访问。

赋值

在初始化方法中,应该直接访问实例变量,代码如下

- (id)initWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName {

    self = [super init];

    if (self) {

        _firstName = aFirstName;  // 直接访问

        _lastName = aLastName;

    }

    return self;

 }

访问:

存取方法

初始化时,应该直接访问实例变量,但是其他地方不要直接访问实例变量,而应该通过存取方法访问。因为在那个时候,实例变量可能还没有被正确赋值。如果通过存取方法访问,会引起问题。

存取方法实例:

// 存方法

-(void)setName:(NNString *)name

{

    _name=name;

}

// 取方法

-(NNString *)name

{

    return _name;

}

声明一个属性,等于隐式地为响应名称的实例变量声明一对存取方法,更加简便。也就说在头文件写在这一行代码

@property NNString *name

编译器会自动生成实例变量_name,取方法name,和存方法setName

当默认的存取方法无法满足需求怎么办?比如,某个在赋值后还需要其他操作,则需要自定义属性的存取方法。

-(void)setName:(NNString *)name

{

    _name=name;

    // 其他操作

    ```

}

  

但是此时,编译器就不会为name属性创建存方法,不过仍然会创建取方法。如果我们同时覆盖了存取方法(或者只读属性覆盖了取方法),那么编译器就不会自动创建相应的实例变量_name。有些时候,我们不需要编译器为属性默认生成实例变量,可以同时覆盖属性的读取方法.

比如,有个需求:当某个属性第一次访问的时候,才对它进行初始化:

懒访问

- (XYZObject *)someImportantObject {

    if (!_someImportantObject) {

        _someImportantObject = [[XYZObject alloc] init]; // 直接访问实例变量

    }

    return _someImportantObject;

}

  

合成

其实,在头文件声明属性时,只会生成存取方法声明,为了让属性生成实例变量并实现存取方法,属性必须被合成(synthesized).而通常情况下,编译器会自动合成属性并生成默认的实例变量和存取方法。 我们可以在文件中用@synthesize指令自定义属性合成方式

@synthesize name = _name;

这行代码和编译器自动合成的效果相同,左边的name表示创建存取方法setName和name,右边的name 表示创建name实例变量。

点句法

运行时和存取方法运行时是没有区别的,它们都会调用之前实现的存取方法。但是点句法的可读性更好,Apple官方也坚持使用点句法存取实例变量。

NSString *firstName = somePerson.firstName;

somePerson.firstName = @"Johnny";

  • NSString *firstName = somePerson.firstName 相当于[somePerson firstName]
  • somePerson.firstName = @"Johnny"相当于[ somePerson setFirstName:@"Johnny"];

注意:用点句法操作只读属性,会报编译错误。

关系

实例变量,在对象(object)的生命周期中会一直存在,它所占用的内存是在对象首次创建(alloc)的时候被分配的;而对象销毁时,它占用的内存会被释放。默认情况下,属性被编译器自动合成的时候,会生成相应实例变量和读取方法。

Apple 官方推荐使用property。

属性的特性

任何属性都有三个特性,每个特性有多种类型,用于描述相关存取方法的行为。这三种特性分别是多线程、读写特性、内存管理特性。

多线程特性

多线程特性有两种选择类型,atomic和nonatomic。默认是atomic。这意味着,访问必须是原子操作,不能被其他操作打断。比如,声明一个属性

@property NSObject *implicitAtomicObject;

即使从两个不同的线程同时请求访问implicitAtomicObject(一个存一个取),每次访问(存或取)不能被打断,先存完再取,或者先取完再存。

读写属性

读写属性也有两个特性,readwrite和readonly。编译器会为readwrite特性的属性生成存取方法,如果只有readonly特性,只为该属性生成取方法

内存管理

内存管理属性有四个特性,strong,weak,copy,unsafe_unretained .默认strong.

unsafe_unretained:

对于不需要做内存管理的属性,比如int objProperty 不指向任何对象,不需要做内存管理,可以直接用unsafe_unretained ,它表示存取方法会直接为实例变量赋值。

@property (unsafe_unretained) int objProperty

unsafe_unretained类型的指针指向的对象被销毁时,指针不会自动设为nil,而是成为空指针,因此不安全。但是当处理非对象属性时,是不会出现空指针问题的。

copy

当某个属性是指向其他对象的指针,而且该对象的类有可修改的子类,(比如NSString/NSMutableString)应该将该属性的内存管理特性设置为copy。 比如firstName属性,用了copy属性后,存方法改类似以下:

-(void)setFirstName:(NNString *)firstName

{

_firstName=[firstName copy ];

}

至于所有权问题:copy方法返回的是拥有强引用特性的指针,而收到copy消息的NSString对象不会发生任何 变化;该对象不会获得也不会失去拥有者。

只有可变对象应该设置为copy,而复制不可变对象会浪费内存空间。为了避免不必要的复制,向不可变对象发送copy消息时,会返回指向不可变对象自己的指针。

时间: 2024-10-12 17:06:21

实例变量和属性的相关文章

iOS 成员变量,实例变量,属性变量的区别,联系

在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译器从GCC转换为LLVM(low leve

Objective-C 实例变量与属性的区别

记得刚学习OC时,对实例变量和属性总是不太清楚. 比如下面代码中在打印Person类对象的名字时,什么时候用带“_”的name,NSLog(@"%@",p1->_name); 什么时候用不带“_”的name,NSLog(@"%@",p1.name); 现在回想起来也是挺有意思的过往,写下自己曾经的迷惘,纪念一下青春?.... 首先,使用实例变量编写代码.以及实例变量赋值要用到getter.setter方法. @interface Person : NSObje

【转截】iOS成员变量、实例变量、属性变量三者的联系与区别

一.类Class中的属性property 在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译

iOS实例变量、属性变量二者的联系与区别

一.类Class中的属性property 在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译

(转)Objective-C语言--属性和实例变量

本文转自http://blog.csdn.net/addychen/article/details/39525681 使用Objective-C一段时间了,一直没有弄清楚在Objective-C中属性和实例变量,在这里总结一下,Objective-C中先有的实例变量,需要给外部类使用的用@public声明,内部自己使用的用@private或@protect声明.Objective-C添加了属性后,我觉得Apple的考虑应该是,属性用于对外而实力变量主要用于程序内部使用.这样有利于代码的分离,由于

iOS开发中 类、对象、实例变量、成员变量、属性变量等区别和关系

类(class):具有相同属性和行为等同一类元素等总称,类是一个抽象的概念. 区分是类还是对象,看它能否继续被细分. 在OC中,类是表示对象类型的结构体,对象通过类来获取自身的各种信息.类由两个部分组成:*.h和*.m文件组成. *.m文件中 implemention部分是类的实现部分,内部包含类中的各种信息,包括各种实例方法或类方法. 类别( category):是为现有的类添加新方法的方式,通常以"类名称+类别名称"来命名. 类别中不能添加新的实例变量.但是可以在类别中添加属性.

实例变量(instance var)与属性(@property)的关系

实例变量(instance var)与属性(@property)的关系 Objective-C 2.0之后,声明一个@property name自动产生一个实例变量,名为_name,因此省去实例变量和属性重复输入的麻烦.而使用@synthesize可以改变_name名称.@property和@synthesize不必成对出现. @property name:指示编译器自动合成setter和getter方法,setter方法名即setName,而getter方法名即name.@property后面

iOS基础-属性与实例变量区别

在ios第一版中,我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 最近,苹果将默认编译器从GCC转换为LLVM(low level virtual machine),从此不再

iOS中的成员变量,实例变量,属性变量

在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是以前的用法) @interface MyViewController :UIViewController { UIButton *myButton; } @property (nonatomic, retain) UIButton *myButton; @end 在现在iOS版本中: 苹果将默认编译器从GCC转换为LLVM(low leve