IOS中Object语法的枚举深入理解

在UIKit中对UIButton的理解中, 其中有一个设置如下:
[button setTitle:@"点击" forState:UIControlStateNormal];

其中UIControlStateNormal是一个枚举值,代码如下:
 

typedef NS_OPTIONS(NSUInteger, UIControlState) {
    UIControlStateNormal       = 0,
    UIControlStateHighlighted  = 1 << 0,                  // used when UIControl isHighlighted is set
    UIControlStateDisabled     = 1 << 1,
    UIControlStateSelected     = 1 << 2,                  // flag usable by app (see below)
    UIControlStateFocused API_AVAILABLE(ios(9.0)) = 1 << 3, // Applicable only when the screen supports focus
    UIControlStateApplication  = 0x00FF0000,              // additional flags available for application use
    UIControlStateReserved     = 0xFF000000               // flags reserved for internal framework use
};

这个就很费解了,为啥定义一个宏,还来一个宏定义。有啥猫腻。看看宏是怎么定义的。

//第一个宏:
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)

//CF_OPTIONS跳不进去了,那就只能用强大的GhatGPT了
#define CF_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type

反正这些语法对于现在的我,是完全不能理解的。好歹我之前也是写过一些C/C++应用的,居然这个语法都不能很好的去理解。那接下来咋们就好好全方面的去从底层语法理解吧。

CF_OPTIONS 是一个宏定义,用于定义 Core Foundation 框架中的位掩码类型。

  • _type 表示底层数据类型,咋们这里就是NSInteger整数类型
  • _name 表示类型名称,可以是任何合法的标识符。当前分析的名字就是UIControlState

其中关键宏CF_OPTIONS中,有两个语句块,分别是:

  • enum _name : _type _name;
  • enum _name : _type

现在把焦点放到这两个语句块的分析上面来。

从《Objective-C基础教程》和《Objective-C编程全解》中去看枚举的介绍,基本上没有什么详细的介绍,只是简单的带过。

那么我们就先从C语言语法中去看看枚举类型是什么情况,然后在回头来分析咋们现在的语法。

在C语言中定义枚举类型的方式如下:
 

enum 枚举名称
{
    标识符 = 整型常量,
    标识符 = 整型常量,
    标识符 = 整型常量,
    标识符 = 整型常量
};

我们做一个示例,定义一个枚举名称为Test,拥有TestA、TestB等枚举成员的枚举类型。代码如下:
 

enum Test
{
    TestA = 0,
    TestB = 1,
    TestC = 2,
    TestD = 3
};
  • 注1: 当枚举成员都未设置"=整型常量"时,默认从第一个标识符开始,从0依次递增加1
  • 注2: 当为某个枚举成员设置"=整型常量"时,其后面的标识符会在此基础上依次递增加1

在使用该枚举类型时,我们需要创建一个枚举变量。创建枚举变量的方式如下:
 

enum 枚举名称 枚举变量 = 枚举变量值;

以"创建一个枚举名称为Test的枚举变量test,并为其赋值TestB"为例

enum Test test = TestB;
  • 注: 枚举变量值的取值只能从对应枚举类型的枚举成员中选择

我们也可以在定义枚举类型的同时定义枚举变量,该枚举变量不用初始化,可直接对其进行赋值并使用

enum Test
{
    TestA = 0,
    TestB,
    TestC,
    TestD
} test;
  • 注: 该枚举名称可以省略,直接定义枚举变量即可(称作"匿名枚举")

如上我们针对于枚举进行了一些常识的复习,对于匿名枚举也有了认识。看来,人的记忆曲线持续的事件真的很短,我也就7/8年没有写C,就忘得差不多了。

接下来我们结合typedef一起分析,这样更加接近我们的这次的目的。

通过typedef为枚举类型设置一个"别名",这样便可以像使用int一样使用枚举类型:
 

typedef enum _Test
{
    TestA = 0,
    TestB,
    TestC,
    TestD
} Test;

定义"别名"后,便可采用如下方式定义枚举变量

Test test = TestB;

这样是不是就方便很多了。针对匿名枚举,在通过typedef设置"别名"的形式如下:
 

typedef enum
{
    TestA = 0,
    TestB,
    TestC,
    TestD
} Test;

定义"别名"后,可以和上面非匿名的方式一样:
 

Test test = TestB;

到这里,基础的主要部分都补充完成了。到了核心揭秘的时刻了。

我们把宏部分的代码展开如下:

//第一个语句块
typedef enum UIControlState : NSUInteger UIControlState;

//第二个语句块
enum UIControlState : NSUInteger {
    UIControlStateNormal       = 0,
    UIControlStateHighlighted  = 1 << 0,                  // used when UIControl isHighlighted is set
    UIControlStateDisabled     = 1 << 1,
    UIControlStateSelected     = 1 << 2,                  // flag usable by app (see below)
    UIControlStateFocused API_AVAILABLE(ios(9.0)) = 1 << 3, // Applicable only when the screen supports focus
    UIControlStateApplication  = 0x00FF0000,              // additional flags available for application use
    UIControlStateReserved     = 0xFF000000               // flags reserved for internal framework use
};

这么已展开的话, 那么我们这里又缺失了一个语法的理解。enum UIControlState : NSUInteger。这种语法。通过ChatGPT理解如下:
 

在 Objective-C 中,可以使用 enum 关键字定义枚举类型。语法格式为:

enum EnumName {
    EnumValue1,
    EnumValue2,
    // ...
};

其中 EnumName 表示枚举类型的名称,EnumValue1EnumValue2 等表示枚举值。枚举值默认从 0 开始自增,也可以手动指定枚举值的数值。

在定义枚举类型时,可以使用 : 指定枚举值的底层数据类型。例如,下面的代码定义了一个名为 MyEnum 的枚举类型,底层数据类型为 NSUInteger

enum MyEnum : NSUInteger {
    MyEnumValue1,
    MyEnumValue2
};

这里的 : NSUInteger 表示枚举值的底层数据类型为 NSUIntegerMyEnumValue1 和 MyEnumValue2 是枚举值,它们的数值分别为 0 和 1。

所以这个是Objective-C特有的语法。到目前为止,语法知识补充完毕。

---------------------------------- 核心部分 ---------------------------------------------------------
我们不厌其烦的在一次把宏展开的代码贴到下面:
 

//第一个语句块
typedef enum UIControlState : NSUInteger UIControlState;

//第二个语句块
enum UIControlState : NSUInteger {
    UIControlStateNormal       = 0,
    UIControlStateHighlighted  = 1 << 0,                  // used when UIControl isHighlighted is set
    UIControlStateDisabled     = 1 << 1,
    UIControlStateSelected     = 1 << 2,                  // flag usable by app (see below)
    UIControlStateFocused API_AVAILABLE(ios(9.0)) = 1 << 3, // Applicable only when the screen supports focus
    UIControlStateApplication  = 0x00FF0000,              // additional flags available for application use
    UIControlStateReserved     = 0xFF000000               // flags reserved for internal framework use
};

上面的代码解释如下:
定义了一个UIControlState : NSUInteger的枚举类型的枚举。如下:
枚举中间用了位掩码进行每个具体枚举值的定义。本质和是否用位掩码,还是用给定的数值,其实没有多大的关系的。这个enum语法是做不了限制的。所以很多文章说typedef NS_OPTIONS(NSUInteger, UIControlState)多用于带有移位运算的枚举是不成立的,这个只是君子协议,没有从语法上进行限制的。从目前代码层面的分析

enum UIControlState : NSUInteger {
    UIControlStateNormal       = 0,
    UIControlStateHighlighted  = 1 << 0,                  // used when UIControl isHighlighted is set
    UIControlStateDisabled     = 1 << 1,
    UIControlStateSelected     = 1 << 2,                  // flag usable by app (see below)
    UIControlStateFocused API_AVAILABLE(ios(9.0)) = 1 << 3, // Applicable only when the screen supports focus
    UIControlStateApplication  = 0x00FF0000,              // additional flags available for application use
    UIControlStateReserved     = 0xFF000000               // flags reserved for internal framework use
};

然后通过typedef为枚举类型UIControlState : NSUInteger设置一个"别名"叫UIControlState。这样后续枚举类型UIControlState : NSUInteger就可以用"别名"UIControlState来定义变量。

typedef enum UIControlState : NSUInteger UIControlState;

这段代码最后的分析就是,为啥typedef对枚举类型UIControlState : NSUInteger的"别名"定义前置了,这个从语法上面没有问题么?

目前ChatGPT也没有很好的解答,原本CF_OPTIONS(_type, _name)这个宏定义就是ChatGPT给的。其实也就没有必要进行深究了,除非真的拔开Core Foundation 框架进行真实代码分析了。

今天代码就分析到这里了。

附件一:
本文引用如下信息:
1,《iOS之枚举用法 - 简书
2,GhatGPT的解答。

3,《Objective-C基础教程》

4,《Objective-C编程全解》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值