iOS:枚举和位运算

来源:互联网 发布:美国历年人口数据 编辑:程序博客网 时间:2024/06/13 22:50

今天对iOS的枚举和位运算做一下整理,主要内容如下:

1.iOS中的两个枚举类型:NS_OPTIONS,NS_ENUM

2.枚举使用位运算的原因

3.位运算介绍和扩展


一.枚举类型

一般情况下,我们采用C风格的enum关键字可以定义枚举类型。

    enum{           UIViewAnimationTransitionNone,          UIViewAnimationTransitionFlipFromLeft,          UIViewAnimationTransitionFlipFromRight,          UIViewAnimationTransitionCurlUp,          UIViewAnimationTransitionCurlDown,      } UIViewAnimationTransition;  

    //位移操作枚举定义      enum {          UIViewAutoresizingNone                 = 0,          UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,          UIViewAutoresizingFlexibleWidth        = 1 << 1,          UIViewAutoresizingFlexibleRightMargin  = 1 << 2,          UIViewAutoresizingFlexibleTopMargin    = 1 << 3,          UIViewAutoresizingFlexibleHeight       = 1 << 4,          UIViewAutoresizingFlexibleBottomMargin = 1 << 5      };      typedef NSUInteger UIViewAutoresizing;//使用NSUInteger的地方可以使用UIViewAutoresizing,UIViewAutoresizing相当于NSUInteger的一个别名使用,因此一个UIViewAutoresizing的变量可以直接赋值给NSUInteger  

枚举值一般是4个字节的int值,在64位系统上是8个字节。

在iOS6和Mac OS 10.8以后Apple引入了两个宏来重新定义这两个枚举类型,实际上是将enum定义和#define合二为一,并且采用不同的宏来从代码角度来区分(下文介绍)。

我们可以参考UIKit.Framework的头文件,可以看到大量的枚举定义。

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {    UIViewAnimationTransitionNone,//默认从0开始    UIViewAnimationTransitionFlipFromLeft,    UIViewAnimationTransitionFlipFromRight,    UIViewAnimationTransitionCurlUp,    UIViewAnimationTransitionCurlDown,};typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {    UIViewAutoresizingNone                 = 0,    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,    UIViewAutoresizingFlexibleWidth        = 1 << 1,    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,    UIViewAutoresizingFlexibleHeight       = 1 << 4,    UIViewAutoresizingFlexibleBottomMargin = 1 << 5};

这两个宏的定义在Foundation.framework的NSObjCRuntime.h中:
#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type#if (__cplusplus)#define NS_OPTIONS(_type, _name) _type _name; enum : _type#else#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type#endif#else#define NS_ENUM(_type, _name) _type _name; enum#define NS_OPTIONS(_type, _name) _type _name; enum#endif

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
展开得到

typedef enum UIViewAnimationTransition : NSInteger UIViewAnimationTransition;enum UIViewAnimationTransition : NSInteger {


二.枚举和位运算


从枚举定义来看,NS_ENUM和NS_OPTIONS本质是一样的,而iOS使用两种方式定义的目的是区分使用场景----是否可以"多选".

在系统API中可以看到NS_OPTIONS定义的枚举都采用了位运算作为枚举内容,而NS_ENUM则没有,其原因就是NS_OPTION的枚举值同时使用时(相加)仍具有唯一性,可使用或运算相加进行"多选"操作.位移不同数位得到的枚举数值代表二进制中不同的数位,不同数位相加的结果是唯一的.

多个NS_OPTION的枚举值或运算赋值给结果就如同一个"选项集合"(option),如上代码自适应既可以选择宽度自适应也可以选择高度自适应,各选项之间并不互斥唯一,当使用结果进行判断时,只需要将结果和目标选项进行位与运算,如真则可确认集合中包含了该枚举值.如下:

if (options & SDWebImageDownloaderHighPriority) {            operation.queuePriority = NSOperationQueuePriorityHigh;        }

因此,系统使用NS_OPTIONS时由于使用位运算更多使用在可多选的场合,而NS_ENUM更多使用在枚举结果用于唯一互斥的环境下.

我们自己在实际使用时,我们仍可以直接定义:

typedef enum : NSInteger {....} UIViewAnimationTransition;
并根据需要是否将枚举值定义为位运算来满足多选需求.


三.位运算介绍


枚举及位运算在编程中的应用

位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。C语言提供了6个位操作。运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。这里只用到“按位与”运算符(&)与右移运算符(>>)。

按位与是指:参加运算的两个数据,按二进制位进行与”运算。如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。

右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。

如果我们想获取二进制代码中某位上的值,可以采用与运算,然后根据其所在位进行右移即可。

例:1.获取15二进制代码中的第四位:

15与8进行与运算:15&8

    1111

    1000

    1000

将其右移三位得到:0001

2.获取9的第二位:

  将9与2进行与运算:1001

                     0010

                     0000

将其右移一位得到:0000

编程题目

1.某游戏规则中,甲乙双方每个回合的战斗总是有一方胜利,一方失败。游戏规定:失败的一方要把自己的体力值的1/4加给胜利的一方。例如:如果双方体力值当前都是4,则经过一轮战斗后,双方的体力值会变为:53

现在已知:双方开始时的体力值甲:1000,乙:2000

假设战斗中,甲乙获胜的概率都是50%

求解:双方经过4个回合的战斗,体力值之差小于1000的理论概率。

解析:双方经过四个回合的战斗,则一共会出现的情况有十六种,因此解决这个问题只需枚举出这十六种情况,计算出甲乙各自的体力值,求出两者之差的绝对值。然后记录小于1000的情况,一次求出概率。

#include<iostream>

#include<cmath>

using namespacestd;

intmain()

{

      int k[3];

      int m = 1000,n = 2000,sum = 0,all = 0;

      for(int i = 0; i <= 15; i ++)  //枚举十六种情况

      {

      k[0] = (i&8) >>3; //>>”右移符号将i8进行&运算即保留i二进制代码的最高位,右移三位得到0,1,代码

        k[1] = (i&4) >>2; //4进行与运算保留左数第二位,右移两位得到01代码

        k[2] = (i&2) >>1; //2进行与运算保留左数第三位,右移一位得到01代码

        k[3] = (i&1);  //1进行与运算直接得到01代码

        for(int j = 0; j <= 3; j++)

        {

               if(k[j] == 0)

               {

                       n+= m*1/4;

                       m =m - m*1/4;

               }

               else

               {

                       m+= n*1/4;

                       n =n - n*1/4;

 

               }

       

        }

        if(abs(m-n) < 1000)

             {

                     sum++ ;

             }

     all++;

      }

      cout<<"体力值的差的绝对值小于1000的概率为"<<sum/(float)(all)<<endl;

      return 0;

}



参考内容:

http://blog.csdn.net/annkie/article/details/9877643
http://blog.sina.com.cn/s/blog_96b292000100yhxt.html

0 0
原创粉丝点击