(OC) 类和对象(上)
(OC) 类和对象(上)
1 类的定义
类的定义严格遵循“接口-实现分离”:
- 接口:声名类的公开成员变量、属性和方法,放在 “.h"文件
- 实现:实现接口中声明方法,放在”.m“文件中
1.1接口部分(.h文件)
接口部分以@interface关键字开始,@end结束,指明继承父类(常为NSObject)
模板:
#import <Foundation/Foundation.h> @interface Person : NSObject { // 成员变量声明区(通常放在大括号内) NSString *_name; // 注意:以下划线开头是约定俗成的命名方式 NSInteger _age; } // 属性声明(自动生成 getter/setter) @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; // 方法声明 - (void)sayHello; - (instancetype)initWithName:(NSString *)name age:(NSInteger)age; @end声明:
#import<Foundation/Foundation.h>引入基础框架,NSObject等的类在这里面@interface Person : NSObject表示Person继承自NSObject- 大括号
{}内是成员变量(实例变量)声明区,现在使用@property来代替直接声明(如@property NSString *_name) @property声明属性,编译器自动生成带下划线的成员变量(如_name)及对应的setter/getter方法。括号内的nonatomic、copy是属性特性- 方法声明以
-(实例方法)或+(类方法)开头,返回值类型用小括号括起,后跟方法名(加:),后是参数类型,最后是参数名.模板格式-(返回值类型)方法名:(参数类型)参数名
1.2实现部分(.m文件)
实现部分以@implementation开始,@end结束,需导入对应头文件
// Person.m #import "Person.h" @implementation Person // 初始化方法 - (instancetype)initWithName:(NSString *)name age:(NSInteger)age { self = [super init]; // 调用父类初始化方法 if (self) { _name = [name copy]; // 直接赋值给成员变量(或使用 self.name = name;) _age = age; } return self;// 返回初始化完成的对象 } // 实现 sayHello 方法 - (void)sayHello { NSLog(@"Hello, my name is %@, I'm %ld years old.", self.name, (long)_age); } @endself:指向当前对象的指针(类似 C 语言的this),代表 “正在初始化的这个对象”。super:指向父类对象的指针,用于调用父类的方法,保证父类部分先完成初始化。- (instancetype)initWithName:age:是一个指定初始化方法(OC 初始化方法必须以init开头),避免空值问题,返回类型用instancetype可以让编译器判断类型[super init]是必须的,会先初始化父类部分,将结果赋值给self。
2 对象的创建与使用
2.1创建对象
Objective-C 中创建对象通常使用alloc和init两步:
Person *person = [[Person alloc] initWithName:@"Alice" age:25];alloc是NSObject的类方法,负责分配内存并返回一个未初始化的实例。init(或自定义的initWith...)负责初始化对象的成员变量,使之处于可用状态。
也可以使用new方法,它等同于调用alloc后跟init(无参数初始化):
Person *person2 = [Person new]; // 如果类提供了无参 init 方法2.2访问属性
// 点语法 person.name = @"Bob"; NSLog(@"Name: %@", person.name); // 消息传递方式 [person setName:@"Bob"]; NSLog(@"Name: %@", [person name]);点语法实际上会被编译器转换为对应的setter/getter方法调用
2.3调用方法
Objective-C 中方法调用采用消息传递机制,格式为[receiver message]:
[person sayHello];// 调用实例方法如果方法带有参数,消息名(方法名)会包含参数标签:
Person *person = [[Person alloc] initWithName:@"Charlie" age:30];这里的initWithName:age:就是完整的方法名,initWithName:和age:都是方法签名的一部分。
3 属性深入了解
@property是 Objective-C 的一大特性,它封装了成员变量的访问,并允许我们声明各种特性来控制生成的方法行为。
3.1属性是什么?
简单说,属性就是类的“特征”或“状态”。比如一个人有姓名、年龄,一辆车有品牌、颜色。在代码中,我们把这些特征称为“属性”。
但属性不仅仅是一个变量,它还封装了对这个变量的访问方式(读取和修改)。在 Objective-C 中,我们用@property来声明一个属性。
3.2为什么需要属性?
在面向对象编程中,有一个重要原则叫封装——我们不希望外部直接访问对象的内部数据,而是通过方法来操作。
如果没有属性,你需要手动为每个成员变量写两个方法:一个取值方法(getter),一个赋值方法(setter)。比如:
// 不使用属性,手动写 getter/setter @interface Person : NSObject { NSString *_name; // 成员变量 } - (NSString *)name; - (void)setName:(NSString *)name; @end @implementation Person - (NSString *)name { return _name; } - (void)setName:(NSString *)name { _name = [name copy]; } @end这样写太繁琐了!而且每个类都要重复这样的模板代码。
属性就是来解决这个问题的。你用一行@property,编译器就自动帮你生成:
- 一个带下划线的成员变量(比如
_name) - getter 方法(
- (NSString *)name) - setter 方法(
- (void)setName:(NSString *)name)
你只需要写:
@interface Person : NSObject @property (nonatomic, copy) NSString *name; @end编译器自动帮你实现了上面那一大段代码。
3.3属性特性分类
属性特性,用来告诉编译器如何生成 getter/setter。
属性的声明格式:
@property (attributes) Type *name;分类:
3.3.1 原子性
atomic(默认):生成的 setter/getter 是原子的,即多线程环境下访问是安全的,但性能稍低。nonatomic:非原子操作,速度更快,但在多线程环境下需要自己保证数据安全。iOS 开发中绝大多数属性都用nonatomic。
3.3.2 读写性
readwrite(默认):同时生成 getter 和 setter。readonly:只生成 getter,不生成 setter,常用于对外只读的属性。
3.3.3 内存管理语义(ARC 下)
assign:直接赋值,适用于基本数据类型(NSInteger、CGFloat 等)和 delegates(避免循环引用)。strong:强引用,表示拥有该对象,会使其引用计数 +1。适用于绝大多数 Objective-C 对象。weak:弱引用,不会增加引用计数,当对象被释放时,属性自动置为 nil。常用于 delegates 和避免循环引用。copy:拷贝对象,常用于NSString、NSArray、NSDictionary等具有可变子类的类型,以确保属性值的独立性。unsafe_unretained:与assign类似,但用于对象类型,不会自动置 nil(不安全,很少使用)。
3.3.4 方法名定制
getter = getterName:指定 getter 方法名,常用于布尔属性(如@property (getter=isFinished) BOOL finished;)。setter = setterName:指定 setter 方法名。
4 方法的种类
4.1实例方法
以-开头,必须通过对象实例调用,用于操作该对象的实例变量。
- (void)someInstanceMethod;4.2类方法
类方法以+开头,通过类名调用,不能访问实例变量(因为没有实例),常用于创建对象(工厂方法)或获取全局信息。
+ (instancetype)personWithName:(NSString *)name;例:
+ (instancetype)personWithName:(NSString *)name age:(NSInteger)age { return [[self alloc] initWithName:name age:age]; }4.3 初始化方法
初始化方法是以init开头的实例方法,用于设置对象的初始状态。遵循以下规范:
- 返回类型为
instancetype。 - 必须先调用父类的初始化方法:
self = [super init]。 - 检查
self是否成功创建,然后初始化成员变量。 - 返回
self。
- (instancetype)init { self = [super init]; if (self) { _name = @"Unknown"; _age = 0; } return self; }5. self 和 super
- self:隐藏参数,代表当前方法的接收者(即当前对象)。在实例方法中指向当前实例,在类方法中指向当前类。
- super:也是一个消息接收者,但指示编译器从父类开始查找方法实现。常用于调用父类的初始化方法或重写的方法。
- (instancetype)init { self = [super init]; // 调用父类的 init // ... return self; }