52个有效方法(6) - 理解“属性”这一概念

52个有效方法(6) - 理解“属性”这一概念,第1张

概述属性 “属性”(property)是OC的一项特性,用于封装对象中的数据。 @property @Property是声明属性的语法(@property = ivar + getter + setter)。 OC对象通常会把其所需的数据保存为各种实例变量(ivar)。实例变量一般通过“存取方法”(accessmethod)来访问。 什么是存取方法:getter 和setter 方法(access m 属性

“属性”(property)是OC的一项特性,用于封装对象中的数据。

@property

@Property是声明属性的语法(@property = ivar + getter + setter)。

OC对象通常会把其所需的数据保存为各种实例变量(ivar)。实例变量一般通过“存取方法”(accessmethod)来访问。

什么是存取方法:gettersetter 方法(access method = getter + setter),其中getter 用于获取变量value, 而setter 用于写入value

@Property可以快速方便的为实例变量创建存取器。

//  Man.h#import <Foundation/Foundation.h>@interface Man : NSObject@property (nonatomic,strong)Nsstring *name;@property (nonatomic,strong)Nsstring *sex;@end

与下面的写法等效

//  Man.h#import <Foundation/Foundation.h>@interface Man : NSObject{    // 实例变量    Nsstring *name;    Nsstring *sex;}// setter- (voID)setname:(Nsstring *)newname;// getter- (Nsstring *)name;// setter- (voID)setSex:(Nsstring *)newSex;// getter- (Nsstring *)sex;@end

通常使用“点语法” 来让编译器自动调用相关的存取方法(access method = getter + setter)。

self. name = @"sky";Nsstring *name = self. name;

点语法有什么优势呢?

省时,省力 :如果使用了属性,编译器会自动编写访问属性所需的方法。这个过程由编译器在编译期执行,看不到这些get set 源代码。

编译器会自动向类中添加适当类型的实例变量,并且在属性名前添加下划线。

如果你不想让编译器自动合成存取方法,则可以自己实现。如果你只实现了其中一个存取方法,那么另一个还是会由编译器来合成。

当我们同时重写了setter and getter方式时,系统会报错,原因是找不到实例变量。其解决方法: 在.m的文件中使用@synthesize

@synthesize

@synthesize是为属性添加一个实例变量名,或者说别名。同时会为该属性生成 setter/getter 方法。

protocol中使用property只会生成settergetter方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性。需要使用@synthesize生成settergetter

当你在子类中重载了父类中的属性,你必须 使用@synthesize来手动合成ivar

当我们同时重写了setter and getter方式时,需要在.m的文件中使用@synthesize

//  Man.m#import "Man.h"@implementation Man@synthesize name = _name;// setter- (voID)setname:(Nsstring *)name{  _name = name;}// getter- (Nsstring *)name{  return _name;}@end

**@synthesize name = _name**

_name是成员变量

name是属性

作用是告诉编译器name属性为_name实例变量生成setter and getter方法的实现

name属性的setter方法是setname,它 *** 作的是_name这个变量

@synthesize中定义与变量名不同的settergetter的命名,以此来保护变量不会被不恰当的访问(setter=<name>这种不常用,也不推荐使用)

//setter=<name>这种不常用,也不推荐使用@property (nonatomic,setter = mySetter,getter = myGetter ) Nsstring *name;@property (nonatomic,getter = isHIDden ) BOol hIDden;

@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize@dynamic都没写,那么默认的就是@syntheszIE var = _var

如果某属性已经在某处实现了自己的 setter/getter,可以使用 @dynamic来阻止 @synthesize 自动生成新的 setter/getter 覆盖。

@dynamic

@dynamic告诉编译器:属性的 settergetter 方法由用户自己实现,不自动生成。(当然对于 Readonly 的属性只需提供 getter 即可)。

假如一个属性被声明为 @dynamic var,然后你没有提供@setter方法和 @getter 方法。编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃。或者当运行到 someVar = var时,由于缺 getter 方法同样会导致崩溃。

编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

//  Man.h#import <Foundation/Foundation.h>@interface Man : NSObject@property (nonatomic,strong)Nsstring *name;@end//  Man.m#import "Man.h"@implementation Man@dynamic name;// setter// - (voID)setname:(Nsstring *)name// {//   _name = name;// }// getter- (Nsstring *)name{  return _name;}@end

调用时会出现崩溃

Man *man = [[Man alloc] init];    man.name = @"sky";//缺 setter 方法会导致程序崩溃    Nsstring *name = man.name;//缺 getter 方法同样会导致崩溃
属性特质 原子性

atomic(默认):atomic意为 *** 作是原子的,意味着只有一个线程访问实例变量(生成的settergetter方法是一个原子 *** 作)。atomic是线程安全的,至少在当前的存取器上是安全的。它是一个默认的特性,但是很少使用,因为比较影响效率。

nonatomicnonatomic意为 *** 作是非原子的,可以被多个线程访问。它的效率比atomic快。但不能保证在多线程环境下的安全性,开发中常用。

开发iOS程序时应该使用nonatomic属性,因为atomic(同步锁)属性严重影响性能。该属性使用了同步锁,会在创建时生成一些额外的代码用于帮助编写多线程程序,这会带来性能问题,通过声明nonatomic可以节省这些虽然很小但是不必要额外开销。

存取器控制

reaDWrite(默认):reaDWrite是默认值,表示该属性同时拥有settergetter

ReadonlyReadonly表示只有getter没有setter

有时候为了语意更明确可能需要自定义访问器的名字。

//setter=<name>这种不常用,也不推荐使用@property (nonatomic,getter = myGetter ) Nsstring *name;  @property (nonatomic,getter = isHIDden ) BOol hIDden;
内存管理

assign(默认):assign用于非指针变量(值)类型,统一由系统栈进行内存管理。一般用于基础类型和C数据类型,如intfloatdoubleNSIntegerCGfloat等表示单纯的复制。还包括不存在所有权关系的对象,比如常见的delegate

retain:在setter方法中,需要对传入的对象进行引用计数加1的 *** 作。

strongstrong是在IOS引入ARC的时候引入的关键字,是retain的一个可选的替代。对传入的对象的强引用,会增加对象的引用计数。strongretain的意思相同并产生相同的代码,但是语意上更好更能体现对象的关系。

weak:对传入的对象的弱引用,不增加对象的引用计数,也不持有对象,当对象消失后指针自动指向nil

copy:与strong类似,但区别在于copy是创建一个新对象,strong是创建一个指针,引用对象计数加1

举例说明weakstrongcopy属性特质的差异 首先创建两个自定义的Person类的实例变量,并分别用weakstrong修饰。
@property (nonatomic,strong) Person *strongPerson;@property (nonatomic,weak) Person *weakPerson;
strongPerson属性置nil
self.strongPerson = [[Person alloc] init];self.weakPerson = self.strongPerson;self.strongPerson = nil; NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);

输出结果为:strongStr=(null),weakStr=(null)。说明weak修饰的属性并不会使引用计数增加。

如果使用Nsstring类进行上述类似 *** 作,得到的结果是不同的。
@property (nonatomic,strong) Nsstring *strongStr;@property (nonatomic,weak) Nsstring *weakStr;···self.strongStr = @"string";self.weakStr = self.strongStr;self.strongStr = nil;NSLog(@"strongStr=%@,self.strongStr,self.weakStr);

输出结果为:strongStr=(null),weakStr=string。这里主要是因为Nsstring类型的赋值默认会加上copy,而copy会创建一个新的对象。这里的赋值语句其实是

self.strongStr = [@"string" copy];self.weakStr = [self.strongStr copy];
weakPerson属性置nil
self.strongPerson = [[Person alloc] init];self.weakPerson = self.strongPerson;self.weakPerson = nil;NSLog(@"strongStr=%@,self.weakPerson);

输出结果如下:strongStr=<Person: 0x600000007d50>,weakStr=(null)。说明weak修饰的属性只是对对象的弱引用,并不会真正的持有该对象。

新建一个Person类实例变量p,赋值strongPerson后将pnil
Person *p = [[Person alloc] init];self.strongPerson = p;self.weakPerson = self.strongPerson;p = nil; NSLog(@"strongStr=%@,self.weakPerson);

输出结果为:strongStr=<Person: 0x600000200b50>,weakStr=<Person: 0x600000200b50>。因为strong属性会强引用该对象并使该对象的引用计数+1,所以即使把p设置为nil,该对象也并没有释放,要想释放该对象,还得把strongStr设置为nil:self.strongPerson = nil;。这样输出结果才为 strongStr=(null),weakStr=(null)

在给Person类加了一个name属性。并用copy修饰 :(@property (nonatomic,copy) Nsstring *name)。
Nsstring *a = @"xiaoming";Person *p = [[Person alloc] init];p.name = a;NSLog(@"before p.name=%@",p.name);a = @"xiaohua";NSLog(@"after p.name=%@",p.name);

输出结果:before p.name=xiaomingafter p.name=xiaoming。因为copy关键字修饰的属性是将对象拷贝一份赋值,所以你改变原对象并不会对拷贝后的对象有任何改变。

注:用@property声明 NsstringNSArrayNSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableStringNSMutableArrayNSMutableDictionary,他们之间可能进行赋值 *** 作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份.

要点

可以用@property语法来定义对象中所封装的数据。

通过“修饰词”来指定存储数据所需的正确语义。

在设置属性所对应的实例变量时,一定要遵从该属性所声明的语义。

开发iOS程序时应该使用nonatomic属性,因为atomic(同步锁)属性严重影响性能。

总结

以上是内存溢出为你收集整理的52个有效方法(6) - 理解“属性”这一概念全部内容,希望文章能够帮你解决52个有效方法(6) - 理解“属性”这一概念所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1018704.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存