iOS - 属性关键字

属性

属性:是OC的一项特性,用于封装对象中的数据。

  • iOS中通常用@property的形式来声明属性,一般为我们认为属性 = setter+ getter + 实例变量
  • 其实@property是一种语法糖,编译器会自动为你的实例变量生成setter和getter方法。你在获取这个属性值(NSLog(@"%@",self.name);)和设置属性值(self.name = @“dasheng”)的时候其实是调用了getter和setter方法获取和设置实例值。编译器帮你生成的实例变量就是你的属性名前面加个下划线。

补充:get和set方法的调用

  • 一般的调用方法,是传统的带中括号[ ]的调用方法
//比如上面的声明是一个Person类
Person* person=[[Person alloc]init];
[person setAge:13];
int age=[person age];
  • 点语法的方式
//点调用
person.age=13;  //.调用出现在=号左边,相当于setter
int age=person.age   //.调用出现在=号的右边,相当于getter
NSLog(@"%i",person.age);//这也是getter

关于get和set的注意点

  1. 属性的setter方法和getter方法是不能同时进行重写的

setter方法和getter方法不能同时进行重写

  1. 在getter方法中最后返回return _age;而不是return self.age, 这是因为点语法实际上是对setter和getter方法的调用,如果在getter方法中调用return self.age的话,就会循环调用。

  2. 声明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;
    //前述语法会将生成的实例变量命名为realname,而不再使用默认的名字name,一般情况下无需修改默认的实例变量名。
    
  • @dynamic:

    它会告诉编译器,不要自动创建实现属性所用的实例变量,也不要为器创建存取方法,这就需要开发者自己来添加属性的实例变量名,动态合成实现getter和setter方法

属性关键字

属性关键字可以分为三种类型:

  1. 读写权限的类型: readonly ,readwrite
  2. 原子类 : atomic ,nonatomic
  3. 引用计数 : retain/strong/copy,assign/unsafe_unretained,weak

系统一般默认的关键字

  • 基本数据:atomic,readweite,assign
  • OC对象:atomic, readwrite,strong

属性关键字之原子类

  1. atomic:默认情况下,由编译器所合成的方法会通过锁定机制确保其原子(atomic)
  2. nonatomic: 如果属性具备nonatomic特质,则不使用同步锁。
  3. 一般都写nonatomic
  • 有效的属性值。若是不加锁的话(即nonatomic),那么其中一个线程正在改写某属性时,另一个线程突然闯入,就有可能读到不准确的数值。
  • 如果开发过iOS程序,你就会发现,所有的属性都声明为 nonatomic。这样做的历史原因是:在iOS程序中使用同步锁的开销较大,这会带来性能问题。一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全”,若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如:一个线程在连续多次读取某属性值的过程中有别的线程在改写该值,那么即便属性声明为atomic,也还是会读到不同的属性值。atomic仅保证了属性的setter/getter的线程安全,并不能保证使用属性的过程是线程安全的。因此,开发iOS程序时一般都会使用nonatomic属性。但是在开发MacOS X程序时,使用atomic属性通常时没有问题的。

属性关键字之读写权限

  • readwrite:拥有“获取方法”(getter)和“设置方法”(setter)readwrite是默认属性
  • readonly:仅拥有“获取方法”(getter)可以直接访问

属性关键字之引用计数

  1. strong
  • 先保留新值,再释放旧值,然后再将新值设置上去。

    在ARC下使用strong不用担心引用计数的问题,会在你不需要该对象时自动将其释放

  • 我持有这个对象,在我使用完它之前,不能销毁。

  • strong可以说是ARC下retain的表现形式

  1. retain
  • 释放旧对象,并使传入的新对象引用计数+1.
  • retain只能修饰oc对象,不能修饰非oc对象,一般用来修饰非NSString 的NSObject类和其子类。
  • retain在ARC环境下使用较少,在MRC下使用效果与strong一致
  1. assign
  • 修饰对象类型时,不改变引用计数

  • 修饰基本数据类型:int、bool ,NSInteger

  • 不能用assign去修饰对象,可以用来修饰基本数据结构

    对象的内存一般被分配到堆上,基本数据类型和oc数据类型一本被分配在栈上。

    如果用assign修饰对象,当对象释放后(因为不存在强引用,离开作用域对象内存可能被回收),指针的地址还是存在的,也就是说指针并没有被置为nil,下次再访问该对象就会造成野指针异常。对象是分配在堆上的,堆上的内存由程序员手动释放。

    用assign修饰基本数据类型或OC数据类型时,因为基本数据类型是分配在栈上的,由系统分配和释放,所以不会造成野指针。

  1. week
  • 不改变被修饰对象的引用计数。
  • 弱引用,指向赋值的对象,所指向的对象被释放之后会自动置为nil
  • 只要对象不在被强引用,那么该对象将会被释放,同时所有的弱指针都将被置为nil。可以避免循环引用。
  • 为这种属性设置新值时既不会保留新值也不会释放旧值,类似与assign
  1. copy
  • 在iOS开发中,一般copy关键字用在NSString、NSArray、NSDictionary等属性字段的修饰符。

  • 假如有一个NSMutableString,现在用他给一个retain(strong)修饰 NSString赋值,那么只是将NSString指向了NSMutableString所指向的位置,并对NSMutbaleString计数器加一,此时,如果对NSMutableString进行修改,也会导致NSString的值修改,原则上这是不允许的. 如果是copy修饰的NSString对象,在用NSMutableString给他赋值时,会进行深拷贝,及把内容也给拷贝了一份,两者指向不同的位置,即使改变了NSMutableString的值,NSString的值也不会改变.

    为了安全,防止NSMutbaleString赋值给NSString时,前者修改引起后者值的变化。

深浅复制

  • 深复制是内容复制,产生新对象,会产生新的内存空间
  • 浅复制是指针复制,没有产生新对象,会增加引用计数
copy关键字:
  1. copy修饰不可变对象、原对象为不可变对象时,将原对象赋值给属性,会将原对象进行copy,此时是浅复制,两个指针指向的是同一个地址。
  2. 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值