[iOS] 属性关键字

前言

属性关键字是一个非常重要的部分在 iOS 开发中,这篇博客是对前面内容的复习以及一些补充。

属性关键字

@propety

属性用于封装对象中的数据,属性的本质是 ivar(实例变量) + setter + getter。

可以用 @property 语法来声明属性,@property 会帮我们自动生成属性的 setter 和 getter 方法的声明。

@synthesize

这是用于自动合成 setter + getter 方法的实现,目前已经不需要这个关键字来帮助我们来实现 setter + getter 方法了,现在可以自动生成相关的方法,可以通过这个关键字来定制我们的 ivar 的名字。

就比如举个例子

objc 复制代码
@property (nonatomic, strong) NSString *name;

如果我这么写编译器会默认生成一个实例变量*_name这时会自动 @synthesize name =_name这样其实 self.name实际上就是访问_name*。

objc 复制代码
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end

@implementation Person
// 手动指定 ivar 名字
@synthesize name = myCustomName;
@end

这时self.name 其实是访问myCustomName。

@dynamic

这个是让我们的编译器不用自动进行*@synathesize*,我们会自己实现,无需产生警告,但是他不会影响*@property*生成的 getter 和 setter 方法的声明,这里体现的是 OC 是一种动态运行的语言。

分类中有关@property 的使用

分类中可以通过*@property这个语法来添加属性,但是这里不会生成对应的实例变量,我们不可以用@synathesize*来合成成员变量。原因是

  1. Category 不能添加成员变量因为运行期内存布局已经固定,如果添加实例变量会破坏类的内部布局。
  2. @synthesize是用来合成成员变量的,而分类中不可以添加成员变量。

重要的几个属性关键词

原子性
  • atomic

    • 含义:生成 getter/setter 是线程安全的,会加锁。
    • 优点:保证多线程小爱取值和赋值不会读写冲突。
    • 缺点:性能差,开发中几乎不用。
  • nonatomic

    • 含义:不保证线程安全,getter/setter 直接操作。
    • 优点:性能好,开发中大部分用它。
内存管理相关
  • strong

    • 含义:强引用,持有对象,引用计数 + 1;
    • 适用:OC 对象的属性(NSString、NSArray、自定义类等)。
  • copy

    • 含义:创建副本(调用 copy 方法),不受外部修改影响。
    • 适用:NSString、NSArray、NSDictionary(尤其是 NSString 防止外部传入 NSMutableString 改变值)。

下面有段代码可以形象的展示出 copy 和 strong 的区别

objc 复制代码
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person1 : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) BOOL age;
@end

NS_ASSUME_NONNULL_END
#import <Foundation/Foundation.h>
#import "Person1.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person1 *p1 = [[Person1 alloc] init];
        NSMutableString *s1 = [NSMutableString stringWithString:@"Apple"];
        p1.name = s1;
        [s1 appendString:@"Android"];
        NSLog(@"%@", p1.name);
    }
    return 0;
}

这是打印结果

如果我把属性中的copy换成strong那么打印结果会发生改变

这里的原因就是person.name的属性是copy,所以创建了新的字符串,这个属于深拷贝,拷贝出来一个新的对象,后面的操作都是对新的对象操作,而我们的实际调用还是原来的对象,所以值不会改变。

而改成strong以后,引用计数会加一本质上是浅拷贝,指针拷贝,这时我们操作,更改他的值就会使原本的对象发生改变。

  • weak

    • 含义:弱引用,不增加引用计数。
    • 特点:当对象释放时,weak 指针会自动置为nil,避免野指针。
    • 适用:delegate 属性,或者避免循环引用。
  • assign

    • 含义:直接赋值,不改变引用计数。
    • 适用:基本数据类型(int、float、BOOL、struct)。
    • 缺点:如果用于对象,会产生野指针。

总结

这里我给出一个表格来去介绍大部分的属性关键字

分类 关键字 作用 说明
原子性 atomic (默认) 保证多线程读写安全 性能差,一般不用
nonatomic 不保证线程安全 性能更好,iOS 开发中几乎都用这个 性能更好,iOS 开发中几乎都用这个
内存管理 strong 对象持有(引用计数 +1) 常用于 OC 对象属性
weak 不持有对象,释放后自动置 nil 常用于避免循环引用(如 delegate) 常用于避免循环引用(如 delegate)
assign 直接赋值,不改变引用计数 适合基本数据类型(int、float、struct),对对象可能产生野指针 适合基本数据类型(int、float、struct),对对象可能产生野指针
unsafe_unretained 和 assign 类似,但对象释放不会置 nil ARC 前常用,ARC 后几乎不用 ARC 前常用,ARC 后几乎不用
copy 创建副本(调用 copy 方法) 常用于 NSString、NSArray、NSDictionary 等不可变对象,防止外部修改 常用于 NSString、NSArray、NSDictionary 等不可变对象,防止外部修改
读写性 readwrite (默认) 生成 getter & setter 外部可读可写
readonly 只生成 getter 外部只读,可在类内写 外部只读,可在类内写
方法名 getter=methodName 自定义 getter 方法名 如 getter=isFinished
setter=methodName 自定义 setter 方法名 如 setter=setFinishedState: 如 setter=setFinishedState:
多线程(很少用) atomic 多线程安全 系统默认,但实际开发常配合 nonatomic
相关推荐
可乐鸡翅yeah_12 小时前
hls.js 切换多个视频源,新手开发常见踩坑
开发语言·前端·javascript·ios·ffmpeg·音视频·safari
传奇开心果编程12 小时前
【Flutter入门练中学】第8课:动画与过渡
android·学习·flutter·ui·ios
传奇开心果编程14 小时前
【Flutter入门练中学】第11课:状态管理进阶与声明式路由
android·学习·flutter·ui·ios
JasonSJX14 小时前
四端自建播放器怎么落地:Android、iOS、tvOS、Tizen 的 DRM 播放 SDK 技术盘点
android·ios·音视频·视频防录屏·加密保护课程·直播安全
k4m7v2pz16 小时前
用中文编程语言写游戏:玄铁语言生命游戏的 macOS 适配实录
游戏·macos·玄铁·生命游戏·中文编程语言·玄铁中文编程
茶底世界之下17 小时前
HDR 曲线为什么必须显式决定:端点钳位还是线性外推
ios
茶底世界之下1 天前
导出进度不是一个百分比:AVFoundation 收尾阶段的状态建模
ios·swift
用户2181697049301 天前
FFmpeg (二) shell echo 数组
objective-c
大熊猫侯佩1 天前
macOS27 上可变界面尺寸 iOS App 揭秘
macos·ios·swiftui
tangzzzfan1 天前
把 ADB 装进 macOS app
macos