iOS开发---属性关键字详解

iOS开发—属性关键字详解

@Property

什么是属性?

  • 属性(property)Objective-C的一项特性,用于封装对象中的数据。这一特性可以令编译器自动编写与属性相关的存取方法,并且保存为各种实例变量。
  • 属性的本质是实例变量与存取方法的结合。@property = ivar + getter + setter
    • 实现流程:
    • 每次增加一个属性,系统都会在 ivar_list中添加一个成员变量的描述,在method_list 中增加settergetter 方法的描述,在 prop_list中增加一个属性的描述,计算该属性在对象中的偏移量,然后给出 settergetter方法对应的实现。在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值,为了能够读取正确字节数,系统对象偏移量的指针类型进行了类型强转。

Property的默认设置

  • 基本数据类型:atomic, readwrite,assign
  • 对象类型:atomic, readwrite, strong

⚠️:注意:考虑到代码可读性以及日常代码修改频率,规范的编码风格中关键词的顺序是:原子性、读写权限、内存管理语义、getter/getter。

关键字

关键字解释
atomic原子性访问
nonatomic非原子性访问,多线程并发访问会提高性能
readwrite此标记说明属性会被当成读写的,这也是默认属性
readonly此标记说明属性只可以读,也就是不能设置,可以获取
strong打开ARC时才会使用,相当于retain
weak打开ARC时才会使用,相当于assign,可以把对应的指针变量置为nil
assign不会使引用计数加1,也就是直接赋值
unsafe_unretain与weak类似,但是销毁时不自动清空,容易形成野指针
copy与strong类似,设置方法会拷贝一份副本。一般用于修饰字符串和集合类的不可变版, block用copy修饰

详解copy

  • copy语法的作用:

    • 产生副本
      • copy返回的是不可变的副本
      • mutableCopy返回的是可变的副本
    • 修改了副本并不会影响源对象,修改了源对象,并不会影响副本。
  • copy使用场景:

    • NSStringNSArrayNSictionary 等等经常使用copy 关键字,是因为他们有对应的可变类型:NSMutableStringNSMutableArrayNSMutableDictionary.为确保对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性
    • block,也经常使用 copy
      • 使用 copy 是从MRC 遗留下来的“传统”,在MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.

      • ARC 中写不写都行:对于block 使用 copy还是 strong效果是一样的,但是建议写上 copy,因为这样显示告知调用者“编译器会自动对 block 进行了 copy 操作.

  • 为什么用@property 声明的NSString(或NSArray,NSDictionary)经常使用 copy 关键字,为什么?如果改用strong关键字,可能造成什么问题?

    • 因为父类指针可以指向子类对象,使用 copy 的目的是为了让本对象的属性不受外界影响,使用 copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本. 如果我们使用是 strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
  • 如何让自定义类可以用 copy 修饰符?如何重写带copy 关键字的 setter?

    • 若想令自己所写的对象具有拷贝功能,则需实现NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopyiogNSMutableCopying 协议,不过一般没什么必要,实现NSCopying 协议就够了
    - (id)copyWithZone:(NSZone *)zone {
        NSObject *copyObj = [[NSObject allocWithZone:zone] init];
        copyObj.name = self.name;
        return copyObj;
    }
    
    - (void)setName;(Mitchell*)name {
        _name = [name copy];
    }
    

atomic与nonatomic

  • 什么是原子性?
    • 并发编程中确保其操作具备整体性,系统其它部分无法观察到中间步骤,只能看到操作前后的结果
  • atomic:原子性的,编译器会通过锁定机制确保settergetter的完整性。
  • nonatomic:非原子性的,不保证settergetter的完整性。
  • 区别:由于要保证操作完整,atomic速度比较慢,线程相对安全;nonatomic速度比较快,但是线程不安全。atomic也不是绝对的线程安全,当多个线程同时调用settergetter时,就会导致获取的值不一样。由于锁定机制开销较大,一般iOS开发中会使用nonatomic,而macOS中使用atomic通常不会有性能瓶颈。
  • 如果对这块不太了解,你可以看一下这篇文章atomic到底不安全在哪?

readwrite与readonly

  • 读写权限不写时默认为 readwrite 。一般可在 .h 里写成readonly,只对外提供读取,在 .m 的Extension中再设置为 readwrite 可进行写入。
//.h文件
@interface MyClass : NSObject
@property (nonatomic, readonly, copy) NSString *name;
@end

//.m文件
@interface MyClass()
@property (nonatomic, readwrite, copy) NSString *name;
@end

比较strong与copy

  • 相同之处:是用于修饰表示拥有关系的对象。
  • 不同之处:strong复制是多个指针指向同一个地址,而copy的复制是每次会在内存中复制一份对象,指针指向不同的地址。
    • NSStringNSArrayNSDictionary等不可变对象用copy修饰,因为有可能传入一个可变的版本,此时能保证属性值不会受外界影响。
  • 注意⚠️:若用strong修饰NSArray,当数组接收一个可变数组,可变数组若发生变化,被修饰的属性数组也会发生变化,也就是说属性值容易被篡改;若用copy修饰NSMutableArray,当试图修改属性数组里的值时,程序会崩溃,因为数组被复制成了一个不可变的版本。

比较assign、weak、unsafe_unretain

  • 相同之处:都不是强引用
  • 不同之处:weak引用的 OC 对象被销毁时, 指针会被自动清空,不再指向销毁的对象,不会产生野指针错误unsafe_unretain引用的 OC 对象被销毁时, 指针并不会被自动清空, 依然指向销毁的对象,很容易产生野指针错误:EXC_BAD_ACCESSassign修饰基本数据类型,内存在栈上由系统自动回收。

@synthesize 和 @dynamic

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

  • @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。

  • @dynamic 告诉编译器:属性的settergetter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)
    假如一个属性被声明为

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值