属性
属性:是OC的一项特性,用于封装对象中的数据。
- iOS中通常用@property的形式来声明属性,一般为我们认为属性 = setter+ getter + 实例变量
- 其实@property是一种语法糖,编译器会自动为你的实例变量生成setter和getter方法。你在获取这个属性值(NSLog(@"%@",self.name);)和设置属性值(self.name = @“dasheng”)的时候其实是调用了getter和setter方法获取和设置实例值。编译器帮你生成的实例变量就是你的属性名前面加个下划线。
补充:get和set方法的调用
Person* person=[[Person alloc]init];
[person setAge:13];
int age=[person age];
person.age=13;
int age=person.age
NSLog(@"%i",person.age);
关于get和set的注意点
- 属性的setter方法和getter方法是不能同时进行重写的
setter方法和getter方法不能同时进行重写
-
在getter方法中最后返回return _age; 而不是return self.age , 这是因为点语法实际上是对setter和getter方法的调用,如果在getter 方法中调用return self.age 的话,就会循环调用。 -
声明set方法和get方法的规范 a. set方法
- 返回值类型必须是(void)。
- 方法名以set开头,set后面跟上成员变量名(去掉下划线)且成员变量名首字母大写。
- 形参名不能和成员变量名相同
- 接收一个参数,参数的类型与成员变量类型一致。
b. get方法
- 返回值类型与成员变量类型一致。
- 方法名与成员变量名(去掉下划线)相同。
- 不需要接收参数
set和get方法
属性关键字和所有权修饰符不一样 
@property/@synthesize/@dynamic语法
-
@property 刚刚我们有讲iOS中通过@property来自动生成setter和getter方法以及实例变量,其实准确来讲,这种说法是不对的,实际上@property只会生成setter,getter的方法声明 -
@synthesize: @synthesize会在编译期创造一个指定的成员变量,并且生成属性的setter和getter方法的实现部分 所以在之前是@property和@synthesize搭配使用,,后来编译器可以属性自动合成,所以现在我们的代码中已经很少看到@synthesize了 然而@synthesize还有另外一个用法,我们也可以使用@synthesize来指定属性对应的实例变量名 @synthesize name = realname;
-
@dynamic: 它会告诉编译器,不要自动创建实现属性所用的实例变量,也不要为器创建存取方法,这就需要开发者自己来添加属性的实例变量名,动态合成实现getter和setter方法
属性关键字
属性关键字可以分为三种类型:
- 读写权限的类型: readonly ,readwrite
- 原子类 : atomic ,nonatomic
- 引用计数 : retain/strong/copy,assign/unsafe_unretained,weak
系统一般默认的关键字
- 基本数据:atomic,readweite,assign
- OC对象:atomic, readwrite,strong
属性关键字之原子类
- atomic:默认情况下,由编译器所合成的方法会通过锁定机制确保其原子(atomic)
- nonatomic: 如果属性具备nonatomic特质,则不使用同步锁。
- 一般都写nonatomic
- 有效的属性值。若是不加锁的话(即nonatomic),那么其中一个线程正在改写某属性时,另一个线程突然闯入,就有可能读到不准确的数值。
- 如果开发过iOS程序,你就会发现,所有的属性都声明为 nonatomic。这样做的历史原因是:在iOS程序中使用同步锁的开销较大,这会带来性能问题。一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全”,若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如:一个线程在连续多次读取某属性值的过程中有别的线程在改写该值,那么即便属性声明为atomic,也还是会读到不同的属性值。atomic仅保证了属性的setter/getter的线程安全,并不能保证使用属性的过程是线程安全的。因此,开发iOS程序时一般都会使用nonatomic属性。但是在开发MacOS X程序时,使用atomic属性通常时没有问题的。
属性关键字之读写权限
- readwrite:拥有“获取方法”(getter)和“设置方法”(setter)readwrite是默认属性
- readonly:仅拥有“获取方法”(getter)可以直接访问
属性关键字之引用计数
- strong
- retain
- 释放旧对象,并使传入的新对象引用计数+1.
- retain只能修饰oc对象,不能修饰非oc对象,一般用来修饰非NSString 的NSObject类和其子类。
- retain在ARC环境下使用较少,在MRC下使用效果与strong一致
- assign
-
修饰对象类型时,不改变引用计数 -
修饰基本数据类型:int、bool ,NSInteger -
不能用assign去修饰对象,可以用来修饰基本数据结构 对象的内存一般被分配到堆上,基本数据类型和oc数据类型一本被分配在栈上。 如果用assign修饰对象,当对象释放后(因为不存在强引用,离开作用域对象内存可能被回收),指针的地址还是存在的,也就是说指针并没有被置为nil,下次再访问该对象就会造成野指针异常。对象是分配在堆上的,堆上的内存由程序员手动释放。 用assign修饰基本数据类型或OC数据类型时,因为基本数据类型是分配在栈上的,由系统分配和释放,所以不会造成野指针。
- week
- 不改变被修饰对象的引用计数。
- 弱引用,指向赋值的对象,所指向的对象被释放之后会自动置为nil
- 只要对象不在被强引用,那么该对象将会被释放,同时所有的弱指针都将被置为nil。可以避免循环引用。
- 为这种属性设置新值时既不会保留新值也不会释放旧值,类似与assign
- copy
-
在iOS开发中,一般copy关键字用在NSString、NSArray、NSDictionary等属性字段的修饰符。 -
假如有一个NSMutableString,现在用他给一个retain(strong)修饰 NSString赋值,那么只是将NSString指向了NSMutableString所指向的位置,并对NSMutbaleString计数器加一,此时,如果对NSMutableString进行修改,也会导致NSString的值修改,原则上这是不允许的. 如果是copy修饰的NSString对象,在用NSMutableString给他赋值时,会进行深拷贝,及把内容也给拷贝了一份,两者指向不同的位置,即使改变了NSMutableString的值,NSString的值也不会改变. 为了安全,防止NSMutbaleString赋值给NSString时,前者修改引起后者值的变化。
深浅复制
- 深复制是内容复制,产生新对象,会产生新的内存空间
- 浅复制是指针复制,没有产生新对象,会增加引用计数
copy关键字:
- copy修饰不可变对象、原对象为不可变对象时,将原对象赋值给属性,会将原对象进行copy,此时是浅复制,两个指针指向的是同一个地址。
- copy修饰不可变对象,原对象为可变对象时,将原对象赋值给属性,会将原对象进行copy,此时是深复制,两个对象指向的不同的地址,属性所指的是可变对象的副本,原对象如果被修改的话,不会影响属性的值,这时对属性进行增删改的操作,就会因为找不到方法而报错。
@property (nonatomic, copy) NSString *strCopy;
NSString *str = @"12345";
person.strCopy = str;
NSLog(@"%p %p", str, person.strCopy);
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@"asdgfg"];
person.strCopy = mutableString;
NSLog(@"%p %p", mutableString, person.strCopy);
[mutableString appendString:@"weret"];
NSLog(@"mutableString - %@ %p, person.strCopy - %@ %p", mutableString, mutableString, person.strCopy, person.strCopy);
2021-07-30 21:51:15.015812+0800 属性关键字[59912:2479739] 0x100002060 0x100002060
2021-07-30 21:51:15.021123+0800 属性关键字[59912:2479739] 0x100620690 0x1f30fa489daca0dd
2021-07-30 21:51:15.049619+0800 属性关键字[59912:2479739] mutableString - asdgfgweret 0x100620690, person.strCopy - asdgfg 0x1f30fa489daca0dd
strong关键字
由于strong修饰属性在设置新值时,在setter方法中保留新值、并释放旧值,将新值设置上去,此时与原对象指向的是同一地址。 当原对象为可变对象时,将原对象赋给strong修饰的不可变对象,修改原对象,那我们不可变的对象也会随之改变
@property (nonatomic, strong) NSString *strCopy;
NSString *str = @"12345";
person.strCopy = str;
NSLog(@"%p %p", str, person.strCopy);
NSMutableString *mutableString = [[NSMutableString alloc] initWithString:@"asdgfg"];
person.strCopy = mutableString;
NSLog(@"%p %p", mutableString, person.strCopy);
[mutableString appendString:@"weret"];
NSLog(@"mutableString - %@ %p, person.strCopy - %@ %p", mutableString, mutableString, person.strCopy, person.strCopy);
0x100001060 0x100001060
0x10072baf0 0x10072baf0
mutableString - asdgfgweret 0x10072baf0, person.strCopy - asdgfgweret 0x10072baf0
|