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

(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方法。括号内的nonatomiccopy是属性特性
  • 方法声明以-(实例方法)或+(类方法)开头,返回值类型用小括号括起,后跟方法名(加:),后是参数类型,最后是参数名.模板格式-(返回值类型)方法名:(参数类型)参数名

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); } @end
  • self:指向当前对象的指针(类似 C 语言的this),代表 “正在初始化的这个对象”。

    super:指向父类对象的指针,用于调用父类的方法,保证父类部分先完成初始化。

  • - (instancetype)initWithName:age:是一个指定初始化方法(OC 初始化方法必须以init开头),避免空值问题,返回类型用instancetype可以让编译器判断类型

  • [super init]是必须的,会先初始化父类部分,将结果赋值给self


2 对象的创建与使用

2.1创建对象

Objective-C 中创建对象通常使用allocinit两步:

Person *person = [[Person alloc] initWithName:@"Alice" age:25];
  • allocNSObject的类方法,负责分配内存并返回一个未初始化的实例。
  • 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:拷贝对象,常用于NSStringNSArrayNSDictionary等具有可变子类的类型,以确保属性值的独立性。
  • 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; }
http://www.jsqmd.com/news/451536/

相关文章:

  • Qwen3-ASR效果实测:RAP歌曲识别准确率突破90%
  • 如何用4步高效实现抖音直播回放下载?实用工具全流程指南
  • 南北阁Nanbeige 4.1-3B一文详解:轻量化≠低质量——3B模型在中文任务上的SOTA表现
  • TQVaultAE:重新定义泰坦之旅装备管理的革命性功能
  • 去AIGC和嘎嘎降AI对比:免费的和付费的差多少?
  • 3个核心功能实现抖音内容高效管理:从批量下载到智能归档指南
  • OpenClaw系列---【OpenClaw如何手动安装skill?】
  • SmallThinker-3B-Preview惊艳效果:QWQ-LONGCOT-500K数据集生成实测分享
  • 新手必看!IndexTTS 2.0保姆级入门:一键生成虚拟主播声音
  • 从老旧代码到现代风格:coze-loop AI优化全流程解析
  • 2026国内最新环保板材十大品牌综合评估:环保升级常态化,HENF级成高端市场标配,技术创新与健康标准双维度解析 - 十大品牌榜
  • CVPR 2022获奖模型实战:MogFace人脸检测从安装到出图全流程
  • EXP-301 第二章
  • Java面试必备:LiuJuan20260223Zimage八股文精讲
  • 基于yz-bijini-cosplay的虚拟直播系统开发
  • translategemma-4b-it中小团队:嵌入内部Wiki系统实现知识图谱图片自动翻译
  • 1.1计算机系统结构的基本概念
  • 别再重试了!MCP Sampling接口幂等性失效的真相(附RFC 9458兼容性补丁+Go/Java双语言SDK修复代码)
  • AIGlasses_for_navigation部署教程:将AIGlasses_for_navigation封装为Docker微服务
  • 直播回放下载技术突破:从内容流失到价值变现的全流程革新
  • YOLOv12数据采集实战:编写Python爬虫构建自定义数据集
  • 圣女司幼幽-造相Z-Turbo在Ubuntu服务器上的无头(Headless)模式部署与管理
  • Qwen3-0.6B-FP8模型轻量化解析:FP8量化技术原理与效果
  • 开源大模型实战:Z-Image-Turbo文生图服务在本地GPU的完整部署流程
  • SeqGPT-560M效果展示:合同/简历/新闻中人名、公司、金额全自动结构化
  • DeepSeek-R1-Distill-Qwen-1.5B环境搭建:简单几步完成模型服务部署
  • translategemma-27b-it实操手册:基于Ollama WebUI定制多语言切换翻译界面
  • WAN2.2文生视频开箱即用体验:在CSDN星图镜像广场一键部署,快速开始创作
  • TQVaultAE:重构装备管理逻辑的泰坦之旅存储解决方案
  • RexUniNLU GPU算力适配指南:torch 1.11+环境下CUDA 11.3/11.7兼容配置