您的位置:首页 > 移动开发 > IOS开发

ios 属性和实例变量的区别

2015-12-09 10:41 375 查看
一、类Class中的属性property

 在ios早期版本中:

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

注意:(这个是以前的用法)

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


在现在iOS版本中:

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

注意:(ios5更新之后,苹果是建议以以下的方式来使用)

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


注意:(1)因为编译器会自动为你生成以下划线开头的实例变量_myButton,不需要自己手动再去写实例变量。而且也不需要在.m文件中写@synthesize
myButton,也会自动为你生成setter,getter方法。

(2)如果.m文件中写了@synthesize myButton,那么生成的实例变量就是myButton;如果没写@synthesize myButton,那么生成的实例变量就是_myButton。所以跟以前的用法还是有点细微的区别。

(3)如果.m文件中写了@synthesize myButton = xxx时 实例变量是xxx,不在是myButton,也不是_myButton,当然xxx可以是任何你想取得名字。

@property与@synthesize作用

@property的作用:(1)让编译器为你自动声明setter与getter方法 (2)如果没发现匹配的实例变量的属性,就自动创建一个以下划线开头的实例变量.

例如:

@property int count;
等效于在头文件中声明2个方法:
- (int)count;
-(void)setCount:(int)newCount;


  @synthesize的作用:(1)让编译器为你自动实现setter与getter方法。(2)可以指定与属性对应的实例变量,例如@synthesize myButton = xxx;那么self.myButton其实是操作的实例变量xxx,而不是_myButton了

例如:

@synthesize count;
等效于在实现文件(.m)中实现2个方法。
- (int)count  {
return count;
}
-(void)setCount:(int)newCount  {
count = newCount;
}


总之就是:property声明了一些成员变量的访问方法,synthesize则定义了由property声明的方法。

他们之前的对应关系是:

property 声明方法 ->头文件中申明getter和setter方法;

synthesize定义方法 -> m文件中实现getter和setter方法。

在Xcode4.5及以后的版本中,可以省略@synthesize,编译器会自动帮你加上get 和 set 方法的实现,并且默认会去访问_age这个成员变量,如果找不到_age这个成员变量,会自动生成一个叫做 _age的私有成员变量。
二、类别中的属性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方法。

  注意一点,

匿名类别(匿名扩展)是可以添加实例变量的,非匿名类别是不能添加实例变量的,只能添加方法,或者属性(其实也是方法)。

成员变量用于类内部,无需与外界接触的变量。

根据成员变量的私有性,为了方便访问,所以就有了属性变量。属性变量的好处就是允许让其他对象访问到该变量。当然,你可以设置只读或者可写等,设置方法也可自定义。所以,属性变量是用于与其他对象交互的变量。

一些建议:

1.如果只是单纯的private变量,最好声明在implementation里.

2.如果是类的public属性,就用property写在.h文件里

3.如果自己内部需要setter和getter来实现一些东西,就在.m文件的类目里用property来声明

三、成员变量、实例变量、属性变量的联系

@interface MyViewController :UIViewControlle

{

UIButton *yourButton;

int count;

id data;

}

@property (nonatomic, strong) UIButton *myButton;

@end

 在{ } 中所声明的变量都为成员变量。所以yourButton、count、data都是成员变量。既然如此,实例变量又是什么意思呢?

  实例变量本质上就是成员变量,只是实例是针对类而言,实例是指类的声明。{ }中的yourButton就是实例变量。id 是OC特有的类,本质上讲id等同于(void *)。所以id data属于实例变量。

  成员变量用于类内部,无需与外界接触的变量。因为成员变量不会生成set、get方法,所以外界无法与成员变量接触。根据成员变量的私有性,为了方便访问,所以就有了属性变量。属性变量的好处就是允许让其他对象访问到该变量(因为属性创建过程中自动产生了set 和get方法)。当然,你可以设置只读或者可写等,设置方法也可自定义。所以,属性变量是用于与其他对象交互的变量。

  综上所述可知:成员变量是定义在{}号中的变量,如果变量的数据类型是一个类则称这个变量为实例变量。因为实例变量是成员变量的一种特殊情况,所以实例变量也是类内部使用的,无需与外部接触的变量,这个也就是所谓的类私有变量。而属性变量是用于与其他对象交互的变量。

  但是,现在大家似乎都不怎么喜欢用成员变量来定义类的变量,都喜欢用属性变量来定义类的变量。把需要与外部接触的变量定义在.h文件中,只在本类中使用的变量定义在.m文件中。
四、知识补充:

1) 什么是类扩展 (Class Extension也有人称为匿名分类)

作用:

能为某个类附加额外的属性,成员变量,方法声明

一般的类扩展写到.m文件中

一般的私有属性写到类扩展

使用格式:

1>匿名分类

@interface Mitchell()
//属性
//方法
@end

与分类的区别:分类的小括号中必须有名字

2>非匿名类别

@interface 类名(分类名字)
/*方法声明*/
@end@implementation类名(分类名字)
/*方法实现*/
@end


分类只能扩充方法,不能扩展属性和成员变量(如果包含成员变量会直接报错)。

如果分类中声明了一个属性,那么分类只会生成这个属性的set、get方法声明,也就是不会有实现(所以必须自己实现)

2)什么是GCC?

“ GCC(GNU Compiler Collection,GNU编译器套装),是一套由GNU开发的编程语言编译器。

GCC原名为GNU C语言编译器(GNU C Compiler),因为它原本只能处理C语言。GCC很快地扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,以及Go与其他语言。原本用C开发,后来因为LLVM、Clang的崛起,令GCC更快将开发语言转换为C++。许多C 的爱好者在对C++一知半解的情况下主观认定C++的性能一定会输给C,但是Taylor给出了不同的意见,并表明C++不但性能不输给C,而且能设计出更好,更容易维护的程序
” 由于GCC已成为GNU系统的官方编译器(包括GNU/Linux家族),它也成为编译与创建其他操作系统的主要编译器,包括BSD家族、Mac OSX、NeXTSTEP与BeOS。

总结:

mac之前的cocoa框架便是用GCC编译的,所以ios与mac os都是默认使用的GCC编译器(现在是clang与llvm,下面会有介绍)

android的系统层因为是linux内核,自然也是GCC编译的,但是android的app因为是运行在Dalvik虚拟机,所以用的不是GCC。

3)什么是LLVM?

“ LLVM,它是一个编译器的基础建设,以C++写成。它是为了任意一种编程语言写成的程序,利用虚拟技术,创造出编译时期,链结时期,运行时期以及“闲置时 期”的优化。在Xcode4之后,苹果将Xcode的默认编译器变成了LLVM

Apple(包括中后期的NeXT) 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错,但Apple对编译工具会提出更高的要求。

一方面,是Apple对Objective-C语言(甚至后来对C语言)新增很多特性,但GCC开发者并不买Apple的帐——不给实现,因此索性后来两者分成两条分支分别 开发,这也造成Apple的编译器版本远落后于GCC的官方版本。另一方面,GCC的代码耦合度太高,不好独立,而且越是后期的版本,代码质量越差,但Apple 想做的很多功能(比如更好的IDE支持)需要模块化的方式来调用GCC,但GCC一直不给做,从根本上限制了LLVM-GCC的开发。 所以,这种不和让Apple一直 在寻找一个高效的、模块化的、协议更放松的开源替代品,于是Apple请来了编译器高材生Chris
Lattner, LLVM就这样产生了。

4)@property属性的其它语义

(1)、设置访问方法的名字

默认的getter和setter器的名称是和变量名关联的,一定是setVirableName和virableName,比如上面的变量age,setter是setAge,getter是age。

可以通过设置@property中的setter和getter属性来修改setter和getter器的方法名。

getter=getterName

setter=setterName

举个例子:

@property (getter=show1,setter=show2:) int age;//现在,它的getter和setter的方法名字就变了<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">  </span>
注意:如果你设置了readonly属性的话,那么你就不应该设置setter属性,要不然会给出一个编译器的警告。

(2)、设置只读或读写

下面两个属性很好理解,

readwrite:表示既有getter,也有setter

readonly:表示只有getter,没有setter

这两个属性是互相排斥的,只能存在一个。

(3)、定义setter的语义

下面的属性指定setter语义设置访问器。他们是互相排斥的。

strong:指定有很强的(拥有)关系到目标对象。

weak:指定有弱(non-owning)关系到目标对象。如果目的地对象销毁,属性值将自动设置为nil。(弱属性不支持OS X上的v10.6和iOS 4,使用指定取而代之)。

copy:调用原始对象的copy()方法,创建一个原始对象的副本,用于分配给新的引用。原始的对象在调用release方法。当然这个属性只用于实现了NSCopying协议的对象类型。

assign:指定使用简单的赋值的setter。这个属性是违约。  使用这个属性对于标量的类型(如NSInteger和CGRect等);

retain: 指定retain应该调用对象上的。原始的对象在调用release。在OS X v10.6和之后,您可以使用这个关键字用于内存管理方面。

(4)、访问属性的线程安全

nonatomic:表示不考虑线程安全
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: