我正在寻找枚举 objc 对象(例如 NSString)的方法,我记得 Xcode4+ 版本中有一个新功能,它提供了一种新的枚举方式,但不清楚。有人知道吗?
7 回答
好的,我自己回答。猜我犯了一个错误。
这是我上面提到的新功能:
typedef enum Language : NSUInteger{
     ObjectiveC,
     Java, 
     Ruby, 
     Python, 
    Erlang 
}Language;
这只是 Xcode 4.4 中枚举的一种新语法,但我很愚蠢地认为我们可以将“NSUInteger”交换为“NSString”。
所以这是我发现可行的方法:
http://longweekendmobile.com/2010/12/01/not-so-nasty-enums-in-objective-c/
// Place this in your .h file, outside the @interface block
typedef enum {
    JPG,
    PNG,
    GIF,
    PVR
} kImageType;
#define kImageTypeArray @"JPEG", @"PNG", @"GIF", @"PowerVR", nil
...
// Place this in the .m file, inside the @implementation block
// A method to convert an enum to string
-(NSString*) imageTypeEnumToString:(kImageType)enumVal
{
    NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
    return [imageTypeArray objectAtIndex:enumVal];
}
// A method to retrieve the int value from the NSArray of NSStrings
-(kImageType) imageTypeStringToEnum:(NSString*)strVal
{
    NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
    NSUInteger n = [imageTypeArray indexOfObject:strVal];
    if(n < 1) n = JPG;
    return (kImageType) n;
}
供参考。第二个示例代码的原作者为枚举处理创建了一个类别。只是添加到您自己的 NSArray 类定义中的东西。
@interface NSArray (EnumExtensions)
- (NSString*) stringWithEnum: (NSUInteger) enumVal;
- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def;
- (NSUInteger) enumFromString: (NSString*) strVal;
@end
@implementation NSArray (EnumExtensions)
- (NSString*) stringWithEnum: (NSUInteger) enumVal
{
    return [self objectAtIndex:enumVal];
}
- (NSUInteger) enumFromString: (NSString*) strVal default: (NSUInteger) def
{
    NSUInteger n = [self indexOfObject:strVal];
    if(n == NSNotFound) n = def;
    return n;
}
- (NSUInteger) enumFromString: (NSString*) strVal
{
    return [self enumFromString:strVal default:0];
}
@end
    使用结构的另一种方法:
extern const struct AMPlayerStateReadable
{
    __unsafe_unretained NSString *ready;
    __unsafe_unretained NSString *completed;
    __unsafe_unretained NSString *playing;
    __unsafe_unretained NSString *paused;
    __unsafe_unretained NSString *broken;
} AMPlayerState;
const struct AMPlayerStateReadable AMPlayerState =
{
    .ready = @"READY",
    .completed = @"COMPLETE",
    .playing = @"PLAYING",
    .paused = @"PAUSED",
    .broken = @"BROKEN"
};
然后你可以像这样使用:
NSString *status = AMPlayerState.ready;
易于使用,可读性强。如果有人用这种方法的优点/缺点更新/编辑答案会很好。
苹果文档的推荐方式:
您可以使用 NS_TYPED_ENUM 对具有您指定的原始值类型的常量进行分组。将 NS_TYPED_ENUM 用于在逻辑上无法在 Swift 扩展中添加值的常量集,并将 NS_TYPED_EXTENSIBLE_ENUM 用于可以在扩展中扩展的常量集。 苹果文档
typedef NSString *MyEnum NS_TYPED_ENUM;
extern MyEnum const MyEnumFirstValue;
extern MyEnum const MyEnumSecondValue;
extern MyEnum const MyEnumThirdValue;
在 .h 文件中。在 .m 文件中定义您的字符串
MyEnum const MyEnumFirstValue = @"MyEnumFirstValue"
MyEnum const MyEnumSecondValue = @"MyEnumSecondValue";
MyEnum const MyEnumThirdValue = @"MyEnumThirdValue";
在 Objective-C 中都按预期工作
- (void)methodWithMyEnum:(MyEnum)myEnum { }
和斯威夫特
func method(_ myEnum: MyEnum) { }
    这将由编译器验证,因此您不会意外混淆索引。
NSDictionary *stateStrings =
 @{
   @(MCSessionStateNotConnected) : @"MCSessionStateNotConnected",
   @(MCSessionStateConnecting) : @"MCSessionStateConnecting",
   @(MCSessionStateConnected) : @"MCSessionStateConnected",
  };
NSString *stateString = [stateStrings objectForKey:@(state)];
<nbsp;>
var stateStrings: [MCSessionState: String] = [
    MCSessionState.NotConnected : "MCSessionState.NotConnected",
    MCSessionState.Connecting : "MCSessionState.Connecting",
    MCSessionState.Connected : "MCSessionState.Connected"
]
var stateString = stateStrings[MCSessionState.Connected]
更新:一种更快捷的方法是扩展CustomStringConvertible符合性的枚举。此外,通过这种方式,编译器将确保实现对底层枚举的每个新添加(而使用数组则不会),因为switch语句必须是详尽的。
extension MCSessionState: CustomStringConvertible {
    
    public var description: String {
        switch self {
        case .notConnected:
            return "MCSessionState.notConnected"
        case .connecting:
            return "MCSessionState.connecting"
        case .connected:
            return "MCSessionState.connected"
        @unknown default:
            return "Unknown"
        }
    }
}
// You can use it like this.
var stateString = MCSessionState.connected.description
// Or this.
var stateString = "\(MCSessionState.connected)"
    2017年更新
最近的反对票引起了我的注意,我想补充一点,enum现在真的很容易使用String:
enum HTTPMethod: String {
    case GET, POST, PUT
}
HTTPMethod.GET.rawValue == "GET" // it's true
原始答案
不幸的是,我最终使用了:
#define HLCSRestMethodGet       @"GET"
#define HLCSRestMethodPost      @"POST"
#define HLCSRestMethodPut       @"PUT"
#define HLCSRestMethodDelete    @"DELETE"
typedef NSString*               HLCSRestMethod;
我知道这不是 OP 所要求的,但编写实际代码来实现 enum 对我来说似乎是一种矫枉过正。我会将 enum 视为一种语言特性(来自 C),如果我必须编写代码,我会提出一些比 enum 做得更多的更好的类。
更新
Swift 版本似乎更漂亮,虽然性能永远不会那么好。
struct LRest {
    enum HTTPMethod: String {
        case Get = "GET"
        case Put = "PUT"
        case Post = "POST"
        case Delete = "DELETE"
    }
    struct method {
        static let get = HTTPMethod.Get
        static let put = HTTPMethod.Put
        static let post = HTTPMethod.Post
        static let delete = HTTPMethod.Delete
    }
}
我认为您正在寻找内联数组函数。例如
@[@"stringone",@"stringtwo",@"stringthree"];
如果没有,我不确定你是否可以枚举对象。
但是,您可以拥有一个静态字符串数组,并在索引处拥有枚举引用对象。
我就是这样做的,虽然它并不完美。我觉得开关机制可以改进......对哈希碰撞阻力也不是积极的,不知道苹果在引擎盖下使用了什么。
#define ElementProperty NSString *
#define __ElementPropertiesList @[@"backgroundColor", @"scale", @"alpha"]
#define epBackgroundColor __ElementPropertiesList[0]
#define epScale __ElementPropertiesList[1]
#define epAlpha __ElementPropertiesList[2]
#define switchElementProperty(__ep) switch(__ep.hash)
#define caseElementProperty(__ep) case(__ep.hash)
-(void)setValue:(id)value forElementProperty:(ElementProperty)ep;
[self setValue:@(1.5) forElementProperty:epScale];
//Compiler unfortunately won't warn you if you are missing a case
switchElementProperty(myProperty) {
    caseElementProperty(epBackgroundColor):
        NSLog(@"bg");
        break;
    caseElementProperty(epScale):
        NSLog(@"s");
        break;
    caseElementProperty(epAlpha):
        NSLog(@"a");
        break;
}