iOS 性能優(yōu)化之位域,共用體,位運算的使用,節(jié)省空間
1. 位運算方法
@interface Person()
{
struct {
// 位域名 : 位域長
char tall : 1;// 是否高
char rich : 1; // 是否富有
char humor : 1; // 是否幽默
} myself;
char _my;
}
@end
@implementation Person
-(void)setRich:(BOOL)rich{
if (rich) {
_my |= RICH;
} else {
_my &= ~RICH;
}
}
-(void)setTall:(BOOL)tall{
if (tall) {
_my |= TALL;
} else {
_my &= ~TALL;
}
}
-(void)setHumor:(BOOL)humor{
if (humor) {
_my |= HUMOR;
} else {
_my &= ~HUMOR;
}
}
-(BOOL)tall{
BOOL ret = _my & TALL;
return ret;
}
-(BOOL)rich{
BOOL ret = _my & RICH;
return ret;
}
-(BOOL)humor{
BOOL ret = _my & HUMOR;
return ret;
}
#define TALL (1 << 0)
#define RICH (1 << 1)
#define HUMOR (1 << 2)
測試代碼
- (void)testStruct{
Person *per = [[Person alloc] init];
per.tall = YES;
per.rich = NO;
per.humor = YES;
NSLog(@"tall : %d , rich : %d , humor : %d",per.tall,per.rich,per.humor);
}
我們是利用了一個 char 一個字節(jié)的空間的后三位,因為我們每次設置值得時候,都會去和一個宏定義做位運算,而這三個宏定義,其實就是用到了一個字節(jié)的后三位,分別來存儲不同的值,然后將后三位置為0或者1.
2. 位域
@interface Person()
{
struct {
// 位域名 : 位域長
char tall : 1;// 是否高
char rich : 1; // 是否有錢
char humor : 1; // 是否幽默
} myself;
char _my;
}
@end
@implementation Person
-(void)setRich:(BOOL)rich{
myself.rich = rich;
}
-(void)setTall:(BOOL)tall{
myself.tall = tall;
}
-(void)setHumor:(BOOL)humor{
myself.humor = humor;
}
-(BOOL)tall{
BOOL ret = myself.tall;
return ret;
}
-(BOOL)rich{
BOOL ret = myself.rich;
return ret;
}
-(BOOL)humor{
BOOL ret = myself.humor;
return ret;
}
這里其實只占用了一個字節(jié),用到了其中的三位而已,,也就是 0000 0111 ,后面的三位用來存儲我們的三個值,
測試代碼
Person *per = [[Person alloc] init];
per.tall = YES;
per.rich = NO;
per.humor = YES;
NSLog(@"tall : %d , rich : %d , humor : %d",per.tall,per.rich,per.humor);
我們通過斷點,來查看我們的 myself 結構體的值
p/x &(per->myself) - > ((anonymous struct) *) $0 = 0x0000600002b2ae48,然后查看這個地址的值 x 0x0000600002b2ae48 - > 0x600002b2ae48: 05 00 00 00 00 00 00 00 00 00 00 00 00
可以看到 05,也就是 0000 0101,也就是我們的第一位和第三位為1,和我們設置的值是一樣的,由此可以證明,我們使用了一個字節(jié)中的三位,我們再來看下這個結構體的具體存儲內(nèi)容
p/x per->myself
((anonymous struct)) $0 = (tall = 0x01, rich = 0x00, humor = 0x01)
這次是不是一目了然。
如果發(fā)現(xiàn)打印為-1,是因為我們設置為1位,當要補足8位的時候,其余都補1,所以為 1111 1111 , 所以直接在get方法返回的時候 添加 !! , 也就是兩個嘆號就可以了,強制轉(zhuǎn)化為 bool 類型
3. 聯(lián)合體使用
繼續(xù)上代碼
#define TALL (1 << 0)
#define RICH (1 << 1)
#define HUMOR (1 << 2)
@interface Person()
{
struct {
// 位域名 : 位域長
char tall : 1;// 是否高
char rich : 1; // 是否富有
char humor : 1; // 是否幽默
} myself;
// char _my;
union {
char bits;
// 增加代碼的可讀性,相對于這個聯(lián)合體就是說這一個字節(jié)的各個位都是做什么用的,占用幾位,總共是用一個字節(jié)而已
struct {
// 位域名 : 位域長
char tall : 1;// 是否高
char rich : 1; // 是否富有
char humor : 1; // 是否幽默
} my;
} myUnion;
}
@end
@implementation Person
-(void)setRich:(BOOL)rich{
if (rich) {
myUnion.bits |= RICH;
} else {
myUnion.bits &= ~RICH;
}
}
-(void)setTall:(BOOL)tall{
if (tall) {
myUnion.bits |= TALL;
} else {
myUnion.bits &= ~TALL;
}
}
-(void)setHumor:(BOOL)humor{
if (humor) {
myUnion.bits |= HUMOR;
} else {
myUnion.bits &= ~HUMOR;
}
}
-(BOOL)tall{
BOOL ret = myUnion.bits & TALL;
return ret;
}
-(BOOL)rich{
BOOL ret = myUnion.bits & RICH;
return ret;
}
-(BOOL)humor{
BOOL ret = myUnion.bits & HUMOR;
return ret;
}
聯(lián)合體
1. 聯(lián)合體中可以定義多個成員,聯(lián)合體的大小由最大的成員大小決定
2. 聯(lián)合體的成員公用一個內(nèi)存,一次只能使用一個成員
3. 對某一個成員賦值,會覆蓋其他成員的值
4. 存儲效率更高,可讀性更強,可以提高代碼的可讀性,可以使用位運算提高數(shù)據(jù)的存儲效率
其實這個 聯(lián)合體 就是占用一個字節(jié) ,然后聯(lián)合體中可以有多個成員,但是他們是公用一塊內(nèi)存,第一個bits使我們真正用的,第二個定義的結構體就是為了解釋這一個字節(jié)是干嘛用的,各個位是干嘛的,上面的代碼我們再打印一下存儲
p/x per->myUnion
((anonymous union)) $0 = {
bits = 0x05
my = (tall = 0x01, rich = 0x00, humor = 0x01)
}
可以看到 一目了然,下面的 my 結構體其實就是對 bits 的解釋,我們設置了bits 的每一位的值,同時也是對應這個結構體里面的每一位,因為他們是共用體。 0x05 就是 0x0000 0101 ,也就是第一位和第三位為1,my = (tall = 0x01, rich = 0x00, humor = 0x01) 這個不正是告訴我們 每一位是0還是1嗎?
所以 上面的代碼你甚至可以這么寫
-(void)setRich:(BOOL)rich{
myUnion.my.rich = rich;
}
-(void)setTall:(BOOL)tall{
myUnion.my.tall = tall;
}
-(void)setHumor:(BOOL)humor{
myUnion.my.humor = humor;
}
-(BOOL)tall{
BOOL ret = myUnion.bits & TALL;
return ret;
}
-(BOOL)rich{
BOOL ret = myUnion.bits & RICH;
return ret;
}
-(BOOL)humor{
BOOL ret = myUnion.bits & HUMOR;
return ret;
}
或者這么寫
-(void)setRich:(BOOL)rich{
myUnion.my.rich = rich;
}
-(void)setTall:(BOOL)tall{
myUnion.my.tall = tall;
}
-(void)setHumor:(BOOL)humor{
myUnion.my.humor = humor;
}
-(BOOL)tall{
BOOL ret = myUnion.bits & TALL;
return ret;
}
-(BOOL)rich{
BOOL ret = myUnion.bits & RICH;
return ret;
}
-(BOOL)humor{
BOOL ret = myUnion.bits & HUMOR;
return ret;
}
或者這樣
-(void)setRich:(BOOL)rich{
myUnion.my.rich = rich;
}
-(void)setTall:(BOOL)tall{
myUnion.my.tall = tall;
}
-(void)setHumor:(BOOL)humor{
myUnion.my.humor = humor;
}
-(BOOL)tall{
BOOL ret = myUnion.my.tall;
return ret;
}
-(BOOL)rich{
BOOL ret = myUnion.my.rich;
return ret;
}
-(BOOL)humor{
BOOL ret = myUnion.my.humor;
return ret;
}
都是可以的,因為他們是一個公用體,都是一樣的道理,是不是覺得很有意思?