提要
花了几天断断续续的读了下SDWebImage的源码,无意细心看了两个宏定义NS_OPTIONS和NS_ENUM
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions)
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder)
两种宏定义,虽然平时开发过程当中大家采用第二种居多,本着好奇,研究了下这两者的区别,以便识记。
本质都是枚举,用法就不扯淡了,本篇主要看看二者的本质差异。
Test示例
新建一个工程看看
typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
SDWebImageDownloaderLowPriority = 1 << 0
};
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
SDWebImageDownloaeExecutionOrder = 1 << 0
};
我们扒开她的衣服查看异同:
1.Xcode Preprocess
Xcode右上下拉点击Preprocess将宏定义展开,展开后如下所示
typedef enum SDWebImageDownloaderOptions : NSUInteger SDWebImageDownloaderOptions; enum SDWebImageDownloaderOptions : NSUInteger {
SDWebImageDownloaderLowPriority = 1 << 0
};
typedef enum SDWebImageDownloaderExecutionOrder : NSInteger SDWebImageDownloaderExecutionOrder; enum SDWebImageDownloaderExecutionOrder : NSInteger {
SDWebImageDownloaeExecutionOrder = 1 << 0
};
这里你可以看到二者没有任何差别,那么Apple 为何要这么声明呢?看来单纯的展开并不能找到答案
2.深入Foundation
#define NS_ENUM(...) CF_ENUM(__VA_ARGS__)
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
CF_ENUM、CF_OPTIONS进行了中转,那么我们继续深入CoreFoundation/CFAvailability.h查看
// Enums and Options
#define __CF_ENUM_GET_MACRO(_1, _2, NAME, ...) NAME
#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
#define __CF_NAMED_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define __CF_ANON_ENUM(_type) enum : _type
#if (__cplusplus)
#define CF_OPTIONS(_type, _name) _type _name; enum : _type
#else
#define CF_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
#else
#define __CF_NAMED_ENUM(_type, _name) _type _name; enum
#define __CF_ANON_ENUM(_type) enum
#define CF_OPTIONS(_type, _name) _type _name; enum
#endif
看到这里,差不多知道二者本质区别,多了cplusplus条件编译,Apple这样做根本上还是考虑到编译器的兼容性
用法上NS_OPTIONS通常适合定义bitmask做位移组合运算OR(|)、AND(&),当然在Objective-C编译选项下也可以用NS_ENUM没有任何区别,但是编译选项在C++\Objective-C++下就会出现问题,C++ 编译选项下会导致类型不能强转造成的编译问题(譬如enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 不能执行赋值操作),所以要使用NS_OPTIONS,做了编译器兼容c++下都是NSInteger类型这样就不会编译出问题。