目标C中的位掩码

Ear*_*rey 24 bit-manipulation objective-c ios

我想学点掩盖.据我所知,这是将某种类型的二进制值存储到一个变量中的方法.

如果上述假设成立,我认为我可以这样做:

typedef NSUInteger Traits;

enum
{
    TraitsCharacterHonest       = 0,
    TraitsCharacterOptimistic   = 1,
    TraitsCharacterPolite       = 4,
    TraitsCharacterDevious      = 8,
    TraitsPhysicalTall          = 16,
    TraitsPhysicalBeautiful     = 32,
    TraitsPhysicalFat           = 64,
    TraitsPhysicalBigEyes       = 128,
    TraitsPhysicalRedHair       = 256, 
};

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits    *traits;

@end
Run Code Online (Sandbox Code Playgroud)

问题1是,如何为一个人分配更多特征?

问题2是,我是否必须将不断增加的数字用于枚举项目,或者有没有办法表明这一点?

最终我希望实现这样的目标:

Person *john = [[Person alloc] init];

//here code that assigns john three traits: TraitsCharacterHonest,      
//TraitsCharacterOptimistic and TraitsPhysicalBeautiful.
Run Code Online (Sandbox Code Playgroud)

如果我理解正确,价值

john.traits应该是100011.,从右边和每个地方读取代表特定枚举值/特征......和0表示没有它,1表示拥有它.

您能否就语法提出建议并在必要时解释特定方面?

joe*_*ick 60

我建议改变一些事情:

  • 枚举值可以更改为左移一个.在我看来,使写作更容易一些.

  • 您不需要将typedef设置为NSUInteger,您可以直接使用声明枚举类型typedef enum.

  • 并且,正如其他人所提到的,您的属性不应该是指向Traits类型的指针.

我的代码看起来像这样:

typedef enum
{
    TraitsCharacterHonest       = 1 << 0,
    TraitsCharacterOptimistic   = 1 << 1,
    TraitsCharacterPolite       = 1 << 2,
    TraitsCharacterDevious      = 1 << 3,
    TraitsPhysicalTall          = 1 << 4,
    TraitsPhysicalBeautiful     = 1 << 5,
    TraitsPhysicalFat           = 1 << 6,
    TraitsPhysicalBigEyes       = 1 << 7,
    TraitsPhysicalRedHair       = 1 << 8
} Traits;

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (strong, nonatomic) NSString  *name;
@property (assign, nonatomic) Traits     traits;

@end
Run Code Online (Sandbox Code Playgroud)

设置John的特征将如下所示:

Person *john = [[Person alloc] init];

john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
Run Code Online (Sandbox Code Playgroud)

然而,虽然位字段对于学习很有用,但是调试它们真的很痛苦.如果你现在想要打印这个角色的特征,你必须编写如下代码:

NSMutableString *result = [NSMutableString string];

if (self.traits & TraitsCharacterHonest)
{
    [result appendString: @"Honest, "];
}
if (self.traits & TraitsCharacterOptimistic)
{
    [result appendString: @"Optimistic, "];
}
if (self.traits & TraitsCharacterPolite)
{
    [result appendString: @"Polite, "];
}
// etc...
Run Code Online (Sandbox Code Playgroud)

此外,删除特征等操作的语法令人困惑.你必须使用&和一个NOT-ed常数,

// remove 'Tall' trait
john.traits = john.traits & ~TraitsPhysicalTall
Run Code Online (Sandbox Code Playgroud)

如果可以(并且性能不是太大的问题),我更喜欢使用更高级别的功能.也许是一个带字符串常量的NSSet?例如

__unused static NSString *TraitsCharacterHonest = @"TraitsCharacterHonest";
__unused static NSString *TraitsCharacterOptimistic = @"TraitsCharacterOptimistic";
__unused static NSString *TraitsCharacterPolite = @"TraitsCharacterPolite";
// etc...

@interface Person : NSObject

@property (strong, nonatomic) NSString     *name;
@property (assign, nonatomic) NSMutableSet *traits;

@end
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

// adding
[john.traits addObject: TraitsCharacterHonest];
// checking
[john.traits containsObject: TraitsCharacterHonest];
// removing 
[john.traits removeObject: TraitsCharacterHonest];
Run Code Online (Sandbox Code Playgroud)

对我来说更有意义.更重要的是,您可以直接打印特征的描述

NSLog(@"John's traits: %@", john.traits);
Run Code Online (Sandbox Code Playgroud)

你会得到合理的输出.

  • 我还建议在每个变量上加上一个'FlagsMask`后缀,表示该变量有一个位(或者如果你把它们组合起来......'BoldItalicTraitsMask =`BoldTraitsMask | ItalicTraitsMask`),可以用作掩码. (2认同)