OC语言 - 成员变量作用域 | #import和@class
■ 成员变量作用域
作用域主要分为四种
1. @public 公开:在有对象的前提下,任何地方都可以直接访问
2. @private 私有:只能在当前类的对象方法中才能直接访问
3. @protected 受保护:只能在当前类和子类的对象方法中访问
4. @package 框架级:作用域介于私有和公开之间,只要处于同一个框架中就可以直接通过变量名访问
注:在 .m 文件声明的成员变量,因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在此声明的成员变量是私有的,即使 .m 文件中的成员变量使用 @public 修饰也不起作用;同样地,在 .m 中定义的成员变量不能和头文件中的成员变量同名
■ 类的嵌套
代码示例:下面代码中 Car 嵌套了 Tyres
// - Tyres.h
1 #import <Foundation/Foundation.h> 2 3 @interface Tyres : NSObject{ 4 NSString *_brand;// 品牌 5 CGFloat _size; // 尺寸 6 } 7 8 9 - (id)initWithBrand:(NSString *)brand; 10 - (id)initWithSize:(CGFloat)size; 11 - (id)initWithBrand:(NSString *)brand 12 size:(CGFloat)size; 13 14 - (NSString *)brand; 15 - (CGFloat)size; 16 17 - (void)turn; 18 - (void)setBrand:(NSString *)brand; 19 - (void)setSize:(CGFloat)size; 20 21 @end
// - Tyres.m
1 #import "Tyres.h" 2 @implementation Tyres 3 4 - (void)turn{ 5 NSLog(@"轮胎开转!"); 6 } 7 8 - (id)initWithBrand:(NSString *)brand 9 size:(CGFloat)size{ 10 11 _brand = brand; 12 _size = size; 13 return self; 14 } 15 16 - (void)setBrand:(NSString *)brand{ 17 18 _brand = brand; 19 } 20 21 - (NSString *)brand{ 22 23 return _brand; 24 } 25 26 - (void)setSize:(CGFloat)size{ 27 28 _size = size; 29 } 30 - (CGFloat)size{ 31 32 return _size ; 33 } 34 35 - (id)initWithBrand:(NSString *)brand{ 36 37 _brand = brand; 38 return self; 39 } 40 41 - (id)initWithSize:(CGFloat)size{ 42 43 _size = size; 44 return self; 45 } 46 @end
// - Car.h
1 #import <Foundation/Foundation.h> 2 #import "Tyres.h" 3 4 @interface Car : NSObject{ 5 NSString *_brand; 6 CGFloat _price; 7 NSString *_color; 8 9 // Tyres 10 Tyres *_tire; 11 } 12 13 - (void)setTire:(Tyres *)tire; 14 - (Tyres *)tire; 15 16 - (void)setBrand:(NSString *)brand; 17 - (NSString *)brand; 18 19 - (void)setPrice:(CGFloat)price; 20 - (CGFloat)price; 21 22 - (void)setColor:(NSString *)color; 23 - (NSString *)color; 24 25 26 @end
// - Car.m
1 #import "Car.h" 2 #import "Tyres.h" 3 @implementation Car 4 5 - (void)setTire:(Tyres *)tire{ 6 _tire = tire; 7 } 8 9 -(Tyres *) tire{ 10 return _tire; 11 } 12 13 - (void)setBrand:(NSString *)brand{ 14 _brand = brand; 15 } 16 17 - (NSString *)brand{ 18 return _brand; 19 } 20 21 - (void)setPrice:(CGFloat)price{ 22 _price = price; 23 } 24 25 - (CGFloat)price{ 26 return _price; 27 } 28 29 - (void)setColor:(NSString *)color{ 30 _color = color; 31 } 32 33 - (NSString *)color{ 34 return _color; 35 } 36 37 38 @end
// - main.m:重复引用头文件
1 #import <Foundation/Foundation.h> 2 #import "Car.h" 3 #import "Car.h" // #import 只会导入一次 4 #include "Tyres.h" 5 #include "Tyres.h"// #include 不会进行头文件过滤:重复导入一个文件会就出现多次导入的问题 6 // #import 可以认为是 C 语言中 #include 的改进版本,然而它是否能够得到改善仍然是一个争论的问题
■ #import | @class
两者区别
1. #import 会包含这个类的所有信息:包括实体变量和方法;@class 只是告诉编译器,其后声明的名称是类的名称,编译的时告诉编译器:这仅仅是一个类名!我们在头文件中一般只需要知道被引用的类名就可以了,不需要知道其内部的实体变量和方法。所以在头文件中一般使用 @class 来声明类名,而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,就需要使用 #import
2. 在编译效率方面来讲,如果你有 100 个头文件都 #import 了同一个头文件,或者这些文件的引用关系如是 A–>B 且 B–>C 且 C–>D,那么当 D 文件有所变化,所有引用过到它的类 A、B、C 都需要重新编译!如果你的类有足够多,这将耗费大量的时间,而是用 @class 则不会产生这样的情况
3. 在循环依赖方面来讲,比如 A–>B 且 B–>A,使用 #import 相互包含就会出现编译错误,产生死循环的问题。而使用 @class 在两个类的头文件中相互声明,则不会有编译错误出现
代码示例:验证使用 #import 彼此引用头文件所产生的环依赖问题
// - Student.h
1 #import <Foundation/Foundation.h> 2 3 // 问题:两个类都如果都使用 #import 彼此引用,编译报错 4 #import "StuClass.h" 5 6 // 解决方式:任一方使用 @class 即可 7 //@class StuClass; 8 9 @interface Student : NSObject{ 10 StuClass *_stuClass; // 报错原因:Unknown type name 'StuClass' 11 } 12 13 @end
// - StuClass.h
1 #import <Foundation/Foundation.h> 2 3 #import "Student.h" 4 @interface StuClass : NSObject{ 5 Student *_student; 6 } 7 8 @end
【推荐】国内首个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 绘制太阳,地球,月球 运作规律