苹果给同一个矩形类型起NSRect和CGRect两个名字,核心是历史演进+跨平台兼容+框架边界三重原因,并非简单的重复定义。
🕰️ 历史起源:两个独立框架的产物
- NSRect 诞生于早期的 NeXTSTEP 系统,属于 Foundation/AppKit 框架,是 Objective-C 生态的原生命名,所有以
NS为前缀的类型都源自 NeXT 时代的技术遗产。 - CGRect 是苹果推出 macOS 10.2 时,伴随 Core Graphics(Quartz 2D) 图形引擎诞生的,属于纯 C 语言的图形框架类型,前缀
CG直接对应 Core Graphics 模块。
早期32位系统中,两者的内部实现并不完全一致:NSRect的坐标值是float类型,而CGRect在CoreGraphics中定义为更适配图形渲染的结构。
📱 跨平台适配:iOS 诞生后的统一
2007年iOS发布后,苹果为了让移动端图形渲染更高效,在iOS生态中主推Core Graphics体系,所有UIKit控件的frame/bounds都直接使用CGRect。
而macOS上的AppKit生态为了兼容几十年的老代码,继续保留NSRect作为对外接口类型。
为了消除两边的类型差异,苹果在64位系统时代直接把NSRect定义为CGRect的别名(typealias NSRect = CGRect),底层完全合并,彻底解决了跨平台的类型兼容问题。
🧩 命名规范:无命名空间的妥协
Objective-C 本身没有C++/Java那样的命名空间机制,苹果的通用解决方案就是给所有全局类型加模块前缀:
- Foundation/AppKit 体系的所有类型统一加
NS前缀(如NSString、NSArray、NSRect) - Core Graphics 图形体系的所有类型统一加
CG前缀(如CGPoint、CGSize、CGRect)
这种双前缀设计既避免了不同框架间的命名冲突,也让开发者一眼就能判断出一个类型属于哪个技术栈,是Objective-C时代非常经典的命名实践。
✅ 实际开发的影响
现在64位全平台下两者100%等价,你可以完全混用,不需要任何强制转换。唯一的区别只是:
- 写macOS AppKit代码时,用
NSMakeRect()、NSMinX()等NS系列函数更符合老代码习惯 - 写iOS UIKit代码时,用
CGRectMake()、CGRectGetMinX()等CG系列函数是行业通用规范