OC语言 - 点语法 | @property和@synthesize
■ 前言
OC 设计点语法的目的就是为了让其他语言的开发者可以很快的上手该语言,点语法就是让 OC 和其他面向对象的语言很相像!注:点语法的本质是方法的调用,而不是访问成员变量。其实就是转换成相应的 setter/getter 方法,没有 setter/getter 就不能使用点语法
在 OC 中访问成员变量只有一种方式即使用 ->,且是在 @public 修饰的前提下。凡是符合系统默认的 setter/getter 书写格式的方法都可以使用点语法
■ 使用点语法
代码示例:给 Person 中的成员变量 _age 手动匹配上 setter/getter 方法
// - Person.h
1 #import <Foundation/Foundation.h> 2 @interface Person : NSObject 3 { 4 int _age; 5 } 6 7 - (void)setAge:(int)age; 8 - (int)age; 9 10 @end
// - Person.m
1 #import "Person.h" 2 @implementation Person 3 4 - (void)setAge:(int)age{ 5 6 _age = age;// 若写成 self.age = age 则等同 [self setAge:newAge],会无休止地调用自身方法,直至程序 crash 7 } 8 9 - (int)age{ 10 return _age; 11 } 12 13 @end
// - main.m
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 4 int main(int argc, const char * argv[]){ 5 6 @autoreleasepool { 7 8 Person *person = [[Person alloc] init]; 9 person.age = 10; // 同 [person setAge:10] 10 11 int age = person.age;// 同 int age = [person age] 12 NSLog(@"age is %i", age); 13 [person release]; 14 } 15 return 0; 16 17 }
■ property | synthesize
这两个关键字是编译器特性,可以让 Xcode 可以自动生成 getter/setter 的声明和实现!iOS 6 之后 LLVM 编译器引入property autosynthesis,即属性自动合成。换句话说,就是编译器会为每个 @property 添加 @synthesize
1. @property 它可以自动生成某个成员变量的 setter/getter 的声明,比如 @property int age 会自动扩展成下面两句
- (void)setAge:(int)age; - (int)age;
2. @synthesize 帮助生成成员变量的 setter/getter 的实现,比如 synthesize age = _age 会创造一个带下划线前缀的实例变量名,同时使用这个属性生成 getter/setter 方法的实现
注:使用 @synthesize 只有一个目的,就是给实例变量起个别名,或者说为同一个变量添加两个名字
- (void)setAge:(int)age{ _age = age; } - (int)age{ Return _age; }
■ Xcode 4.4 版本之前 | Xcode 4.4 版本之后
代码示例
1. Xcode 4.4 版本之前的 @property 和 @synthesize
// - Person
#import <Foundation/Foundation.h> @interface Person : NSObject // 只负责声明接口,不负责实现 @property int age;
@end
// - Person.m
#import"Person.h" @implementation Person // 负责实现:实例变量、接口实现 @synthesize age = _age; @end
// - main.m
#import <Foundation/Foundation.h> #import "Person.h" int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; [p setAge:18]; NSLog(@"age = %d",p.age); } return 0; }
2. Xcode 4.4 版本之后的 @property 和 @synthesize
// - Person.h
1 #import <Foundation/Foundation.h> 2 @interface Person : NSObject{ 3 4 // 成员变量 5 int _age; 6 double _weight; 7 8 9 } 10 11 // @property 会一并生成 setter/getter 的声明和实现 12 @property int age; 13 @property double weight; 14 @property NSString *name; // 成员变量 _name 也会自动生成 15 16 @end
// - Person.m
#import "Person.h" @implementation Person // @synthesize 的功能已被 @property 所包含,可以弃用掉 @end
// - main.m
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 int main(int argc, const char * argv[]) { 4 @autoreleasepool { 5 6 Person *p = [[Person alloc] init]; 7 p.age = 28; 8 [p setWeight:110.2]; 9 [p setName:@"小白"]; 10 11 NSLog(@"age = %d,name = %@,weight = %0.2f",p.age,p.name,p.weight); 12 } 13 return 0; 14 }
注:Xcode 4.4 后 @property 就独揽了 @property/@synthesize 的功能。需要注意的是这种方式生成的成员变量是 private 的,你可以在声明成员变量的花括号中改变其作用域
3. 当 setter/getter 方法均是手动实现时,那么编译器将不会生成成员变量且编译报错
// - Person.h
1 #import <Foundation/Foundation.h> 2 @interface Person : NSObject 3 // 解决方式 1:同时书写两方法的话,我们只需手动声明该实例变量即可 4 { 5 // NSString *_name; 6 } 7 8 @property (nonatomic, copy) NSString *name; 9 - (void)setName:(NSString *)name; 10 - (NSString *)name; 11 12 @end
// - Person.m
1 #import "Person.h" 2 @implementation Person 3 4 // 解决方式 2:使用 @synthesize 关键字 5 @synthesize name = _name; 6 7 -(void)setName:(NSString *)name{ 8 9 if (_name != name) { 10 _name = name; 11 } 12 } 13 14 -(NSString*)name{ 15 16 return _name; 17 } 18 19 @end
注:使用 @dynamic 可阻止 @synthesize 自动合成!经典的使用场景是你知道已经在某处实现了getter/setter 方法,而编译器不知道的情况
■ 修饰属性的属性
属性三大特性
1. 读写特性
readonly、readwrite;默认 readwrite
readwrite 自动生成 setter/getter
readonly 只会自行生成 getter
2. 原子特性
atomic 原子性 、nonatomic 非原子性 ; 默认是 atomic,但是在开发中一般使用 nonatomic
atomic 会保证在多线程情况下访问实例变量是安全的,它会加上一把线程锁,在使用的时候,会比较耗费资源
nonatomic 不能保证在多线程下是安全的
3. 语义特性
assgin、retain、copy:会决定生成 setter 方法的内部实现细节,默认是 assgin
assgin 代表直接给实例变量赋值,但是对于对象类型会有内存问题,此特性通常适用于基本型
retian 代表生成 setter 方法内部是有内存优化的代码,不再是直接赋值
copy 代表生成 setter 方法内部是有内存优化的代码,不再是直接赋值,值得注意的是仅有接收 NSCoping 协议的类才能写 copy
注:可以在声明属性时重命名方法名称
1 #import <Foundation/Foundation.h> 2 3 @interface Dog : NSObject 4 // 重新声明 setter/getter 方法名称 5 @property(nonatomic,retain,getter = haveName,setter = makeName:) NSString *name; 6 // 等价如下 7 //- (void)makeName:(NSString *)name; 8 //- (NSString *)haveName; 9 10 @property(nonatomic,retain)NSString *sex;// 属性的类型决定 setter 的参数类型以及 getter 的返回值类型 11 @property(nonatomic,assign)NSInteger age;// 属性的名字决定 setter/getter 的方法名 12 @end
■ 结语
@synthesize 关键字
1. @synthesize 属性明 = 实例变量名;意思是将属性的 setter/getter 方法作用于这个变量
2. @synthesize 可以指定与属性对应的实例变量,比如 @synthesize age = _myAge 当我们调用 self.age 时其实是操作的实例变量 _myAge 而不是 _age
3. 禁止 @synthesize。如果某属性已经在某处实现了自己的 setter/getter,可以使用 @dynamic 来阻止 @synthesize 自动生成新的 setter/getter 覆盖
4. 一般情况下无需对属性添加 @synthesize ,但一些特殊情形仍然需要!比如在 protocol 中声明并实现属性时,协议中声明的属性不会自动生成 setter/getter![UIApplicationDelegate window] 就是个典型的例子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律