当前位置: 首页 > news >正文

iOS - 从 @property 开始

核心概念


本质@property 是一组访问器方法的声明 (setter/getter) ,编译器可以自动“合成”「访问器」以及「底层存储(ivar)」,并且允许用点语法调用。

  • 例如:
    @property (nonatomic) NSInteger age;
    
  • 编译器等价(自动合成):
    {NSInteger _age; // 可选的“底层存储” (backing ivar)
    }
    - (NSInteger)age { return _age; }              // getter
    - (void)setAge:(NSInteger)age { _age = age; }  // setter
    

好处

  1. 减少样板代码
  2. 明确所有权
  3. 性能与并发控制
  4. KVC/KVO 友好
  5. 易读易维护

常见属性修饰符


  • 读写性
    • readwrite:可读可写(默认)
    • readonly:只读
  • 原子性
    • atomic:保证“单次访问器调用”的原子性,速度慢。(默认)
      • 注意:atomic慢,且不保证你“对该对象做的一系列操作”是线程安全的;也不保证顺序、事务或对象内部的并发安全,实际场景还是需要显式同步。
    • nonatomic:不做同步,速度快。
  • 内存语义修饰符
    • strong:持有关系,引用计数+1,新值 retain,旧值 release.
      • 场景:一般对象所有权、父持子
    • weak:不持有,引用计数不变,对象释放时指针置空。
      • 场景:避免循环引用,如 delegate,子持父、IBOutlet
      • 注意:访问时可能已经变 nil。
    • copy:生成不可变副本,setter 执行 -(id)copy 方法。
      • 场景:阻止赋值可变对象的后续修改,block入堆。
    • assign:位拷贝,引用计数不变。
      • 场景:用于标量和结构体
      • 注意:对象指针使用 assign 会产生悬垂指针
    • unsafe_unretained:不持有,引用计数不变,对象释放不会置空。
      • 场景:以往无weak可用时使用的。
  • 其他
    • getter=isEnabled/setter=setFoo:指定自定义 setter/getter。
    • class:类属性。

copy相关延伸

strongcopy修饰的 可变/不可变 对象,对其 赋值/拷贝 会发生什么?

属性 -copy -mutableCopy 赋值 NSString 赋值 NSMutableString
(copy) NSString 浅拷贝 深拷贝 浅拷贝 深拷贝
(strong) NSString 浅拷贝 深拷贝 浅拷贝 浅拷贝
(copy) NSMutableString 浅拷贝 深拷贝 浅拷贝 深拷贝
(strong) NSMutableString 深拷贝 深拷贝 浅拷贝 浅拷贝

拷贝:

  • -copy一定返回不可变对象
    • 调用对象实际为「不可变类型」,产生浅拷贝。
    • 调用对象实际为「可变类型」,产生深拷贝,得到「不可变类型」的对象。
  • -mutableCopy一定返回可变对象(一定会深拷贝

赋值:

  • strong修饰的属性赋值,只会产生浅拷贝,属性与赋值对象「可变性」一致。
  • copy修饰的属性赋值,可能深拷贝可能浅拷贝,但是结果一定「不可变」的。
    • 赋值对象是「不可变类型」,产生浅拷贝。
      • 赋值对象是「可变类型」,产生深拷贝,得到「不可变类型」的对象。

提问:那为什么[(copy)NSMutableString copy]会是浅拷贝?

  • 答案: 基于上述结论,我们可以将答案拆分成 2 步。
    • 赋值:copy修饰的NSMutableString类型属性,在赋值时会将目标对象“深拷贝”,变为不可变的NSString。因此,我们的属性self.pStr此时实际指向的是一个NSString(不可变对象)。
    • 拷贝:在对「不可变对象」进行copy操作时,返回“指针级别”的同一对象。
    • 综上,[(copy)NSMutableString copy]会是一个浅拷贝操作。

何时存储(背后存储backing ivar的规则)

  • 会有存储
    • 在类的@interface或类扩展里声明@property
    • 没有显式使用@dynamic,且没有同时手写 setter + getter 的。
  • 不会有存储
    • category里声明的@property
    • 使用@dynamic的, 承诺运行时提供访问器的。
    • 已经实现了 getter + setter 的。
    • 协议@protocol里的@property
    • 类属性。
  • 例外和细节
    • readonly 若你实现了 getter,则不会再自动合成 ivar
    • “类属性”没有ivar实例,通常用static或者其他存储来实现存储。
      @interface Config : NSObject
      @property (class, nonatomic, copy) NSString *build;
      @end@implementation Config
      static NSString *_build;
      + (NSString *)build { return _build; }
      + (void)setBuild:(NSString *)b { _build = [b copy]; }
      @end
      
    • 分类里的属性如何有“存储”?
      • 分类里的属性需要通过关联对象实现存储。
      #import <objc/runtime.h>
      @interface UIView (Badge)
      @property (nonatomic, copy) NSString *badgeText; // 分类里不会有 ivar
      @end@implementation UIView (Badge)
      static const void *kBadgeKey = &kBadgeKey;- (void)setBadgeText:(NSString *)badgeText {objc_setAssociatedObject(self, kBadgeKey, badgeText, OBJC_ASSOCIATION_COPY_NONATOMIC);
      }
      - (NSString *)badgeText {return objc_getAssociatedObject(self, kBadgeKey);
      }
      @end
      

@dynamic@synthesize计算属性

  • @dynamic

    • 作用:告诉编译器,不需要生成访问器和ivar,也不要因为找不到方法而告警。
    • 场景:Core Data 的NSManagedObject子类:
      @interface Book : NSManagedObject
      @property (nonatomic, copy) NSString *title;
      @end@implementation Book
      @dynamic title; // 访问器由运行时(Core Data)注入;编译器不生成也不报缺实现
      @end
      
  • @synthesize

    • 作用:让编译器为@property生成 getter/setter 以及背后存储 ivar,并把属性名映射到自定义 ivar 名。
  • 计算属性

    • 作用:不依赖存储,按需计算。

propertyivar 的区别

  1. ivar == 纯存储
  2. property == 访问这个存储的“方法接口”
  3. 大多数情况使用 self.age,在 init/dealloc/自定义访问器内部 常用 _age 直接访问,避免递归等问题。
http://www.jsqmd.com/news/31473/

相关文章:

  • ESP32 中断
  • 25.11.4随笔联考总结
  • docker 常用命令本地部署打包
  • Linux中读写自旋锁rwlock的实现 - 详解
  • 用古代数论分析电磁波频谱
  • AddressSanitizer (ASan) is a fast memory error detector
  • 「CF1210F2-Marek and Matching (hard version)」题解
  • 详细介绍:【数据结构】考研算法精讲:分块查找的深度剖析 | 从“块内无序、块间有序”思想到ASL性能最优解
  • 通过发射高能电子束来控制宇宙射线
  • ICPC2025西安 游记(VP)
  • 2025年11月汽车水泵轴承源头厂家综合评测与选择指南:徐州优力同创领跑行业
  • 各种物质的在宇宙空间中的无线电频谱分析
  • PQ v.Next 团队项目Alpha阶段分工
  • Rari黑客事件全额赔偿方案详解
  • 2025年11月圆锥滚子轴承厂家权威排行:顶尖制造商徐州优力同创服务指南
  • TOON 格式终于赢了!AI 大模型基准测试揭示惊人真相
  • 2025年11月圆锥滚子轴承厂家榜单:行业领袖深度解析与采购指南
  • Spring进阶- Spring IOC构建原理(二)IOC初始化流程
  • 2025年11月轴连轴承厂家推荐榜:行业领导者徐州优力同创解决方案解析
  • 实用指南:Linux《线程同步和互斥(下)》
  • 大模型应用开发技术路线(中):大模型微调与定制从概念到落地
  • 深入解析:搭建Jenkins gitlab 环境
  • 基于业务知识和代码库增强的大模型生成代码实践
  • 告别 “盲买”!京东 AI 试穿 Oxygen Tryon:让服饰购物从“想象”到“所见即所得”
  • 2025年11月轴连轴承厂家推荐:轴连轴承厂家的创新趋势与选择指南
  • 使用核反应堆喷射等离子体的飞机
  • 完整教程:软件设计师-计算机基础-CPU题型
  • 关于“AI编程”,99%的人都还在用过时的玩法
  • 超人福袋助手,抖音福袋扭蛋机,抖音抢福袋工具
  • P12028 [USACO25OPEN] Moo Decomposition G 题解