iOS - 从 @property 开始

核心概念

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

  • 例如:

    swift 复制代码
    @property (nonatomic) NSInteger age;
  • 编译器等价(自动合成):

    swift 复制代码
    {
        NSInteger _age; // 可选的"底层存储" (backing ivar)
    }
    - (NSInteger)age { return _age; }              // getter
    - (void)setAge:(NSInteger)age { _age = age; }  // setter

好处 :统一内存语义(strong/weak/copy...)、线程原子性控制(atomic/nonatomic)、可读性与 KVC/KVO 兼容。


常见属性修饰符

  • 读写性
    • 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:类属性。

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

  • 会有存储
    • 在类的@interface或类扩展里声明@property。
    • 没有显式使用@dynamic,且没有同时手写 setter + getter 的。
  • 不会有存储
    • 在category里声明的@property。
    • 使用@dynamic的, 承诺运行时提供访问器的。
    • 已经实现了 getter + setter 的。
    • 协议@protocol里的@property。
    • 类属性。
  • 例外和细节
    • readonly 若你实现了 getter,则不会再自动合成 ivar。

    • "类属性"没有ivar实例,通常用static或者其他存储来实现存储。

      swift 复制代码
      @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
    • 分类里的属性如何有"存储"?

      • 分类里的属性需要通过关联对象实现存储。
      swift 复制代码
      #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子类:

      swift 复制代码
      @interface Book : NSManagedObject
      @property (nonatomic, copy) NSString *title;
      @end
      
      @implementation Book
      @dynamic title; // 访问器由运行时(Core Data)注入;编译器不生成也不报缺实现
      @end
  • @synthesize

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

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

Property 和 ivar 的区别

  1. ivar == 纯存储
  2. property == 访问这个存储的"方法接口"
  3. 大多数情况使用 self.age,在 init/dealloc/自定义访问器内部 常用 _age 直接访问,避免递归等问题。
相关推荐
庚鑫12 小时前
iOS 27 兼容放大模式下,keyboardFrame 与 UIScreen.bounds 的坐标差异
ios·objective-c
sakiko_19 小时前
纯Appdelegate控制的老项目适配Xcode27(iOS27SDK)
macos·objective-c·cocoa
andyweike8 天前
iOS语法原理
macos·objective-c·cocoa
青柠之夏cc10 天前
Kotlin Multiplatform:一次编写,全平台运行,2026 年跨平台开发的 “最优解”?
macos·objective-c·cocoa
黑科技iOS上架11 天前
iOS framework/dylib动态库定向加固实战
macos·ios·objective-c·cocoa·审核·ios混淆·执行程序差异化
程序鉴定师14 天前
2026年深圳小程序/App开发公司技术选型指南:从架构设计到交付标准全维度评估
java·小程序·uni-app·php·objective-c
鹤卿12316 天前
「iOS」GCD
开发语言·ios·objective-c
用户21816970493017 天前
FFmpeg (二) shell echo 数组
objective-c
2501_9159090623 天前
移动端开发工具链怎么组合比较好,iOS、Android、跨端三套配置方案
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_9159184123 天前
iOS编程用什么软件好?主流工具Xcode、AppCode、CodeRunner与新兴快蝎对比
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程