1.場景需求
1.假設一輛車需要控制前后左右4個方向或者一架無人機需要控制前后左右上5個方向,那么通常的做法是設置幾個對于的bool值的屬性
代碼如下
由于1個BOOL值屬性占用一個字節,也就是8位,總共就是 8 * 4 = 32位,對象開辟的內存大小由屬性決定的,那么有沒有優化的空間呢?
如果用一個字節0000 1111后四位,從低位到高位1表示是,0表示否,分別表示是否向前后左右,那么只需要1個字節,4個bit就能實現上訴功能了,此種實現方式聯合體位域即可。
@interface LGCar : NSObject
@property (nonatomic, assign) BOOL front; //第0位1表示真,0表示假
@property (nonatomic, assign) BOOL back; //第1位1表示真,0表示假
@property (nonatomic, assign) BOOL left; //第2位1表示真,0表示假
@property (nonatomic, assign) BOOL right; //第3位1表示真,0表示假
@property (nonatomic, assign) char top; //第4-7位1111表示真,0000表示假
@end
2.結構體(struct)和聯合體(union)的區別
結構體中所有變量是共存
的--優點有容乃大
,全面;缺點是struct內存空間的分配是粗放的
,不管用不用,全分配
。
聯合體中是各變量是互斥的
--缺點就是不夠包容;但優點是內存使用更為精細靈活,節省了內存空間
3.LGCar聯合體位域書寫方式
#import "LGCar.h"
#define LGDirectionFrontMask (1 << 0)
#define LGDirectionBackMask (1 << 1)
#define LGDirectionLeftMask (1 << 2)
#define LGDirectionRightMask (1 << 3)
#define LGDirectionTopMask (15 << 4)
@interface LGCar() {
// 聯合體
union {
char bits;
// 位域
struct { // front back left right 順序依次從低位到高位
char front : 1; // front 0 1 = 真,0 = 假
char back : 1; // back 1 1 = 真,0 = 假
char left : 1; // left 2 1 = 真,0 = 假
char right : 1; // right 3 1 = 真,0 = 假
char top: 4; // top 4-7 1111 = 真,0000 = 假
};
} _direction;
}
@end
@implementation LGCar
- (instancetype)init {
self = [super init];
if (self) {
_direction.bits = 0b00000000;
}
return self;
}
// 0000 0001
// 1111 1110
// setFront
- (void)setFront:(BOOL)isFront {
if (isFront) {
_direction.bits |= LGDirectionFrontMask;
} else {
_direction.bits &= ~LGDirectionFrontMask;
}
// 二進制打印看看 _direction.bits
[self logCharToBinarySystem:_direction.bits discription:@"setFront"];
}
// 0000 0010
// 1111 1101
// setBack
- (void)setBack:(BOOL)isBack {
if (isBack) {
_direction.bits |= LGDirectionBackMask;
} else {
_direction.bits &= ~LGDirectionBackMask;
}
// 二進制打印看看 _direction.bits
[self logCharToBinarySystem:_direction.bits discription:@"setBack "];
}
// getFront
- (BOOL)front {
char newFront = _direction.front & LGDirectionFrontMask;
[self logCharToBinarySystem:newFront discription:@"getFront"];
return newFront;
}
// getBack
- (BOOL)back {
char newBack = _direction.back & LGDirectionBackMask;
[self logCharToBinarySystem:newBack discription:@"getBack "];
return newBack;
}
- (void)setTop:(char)top {
if (top) {
_direction.bits |= LGDirectionTopMask;
} else {
_direction.bits &= ~LGDirectionTopMask;
}
[self logCharToBinarySystem:_direction.bits discription:@"setTop "];
}
- (char)top {
char newTop = _direction.bits & LGDirectionTopMask;
[self logCharToBinarySystem:newTop discription:@"getTop "];
return newTop;
}
// 二進制打印
- (void)logCharToBinarySystem:(char)value discription:(NSString *)discription {
printf("%s = ", discription.UTF8String);
for(int i = 0;i < 8; i++) {
if(value & 128)
printf("1");
else
printf("0");
value = value << 1;
}
printf(", print _direction.bits == ");
char bits = _direction.bits;
for (int i = 0; i < 8; i++) {
if(bits & 128)
printf("1");
else
printf("0");
bits =bits << 1;
if (i == 7) {
printf("\n");
}
}
}
4.調用方式
#import "LGCar.h"
void logCharToBinary(char value, char * dis) {
}
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
LGCar *car = [[LGCar alloc] init];
car.front = YES;
logCharToBinary(car.front, "");
car.back = YES;
logCharToBinary(car.back, "");
car.top = 0xF0;
logCharToBinary(car.top, "");
printf("\n開始清零 先front后back\n\n");
car.front = NO;
logCharToBinary(car.front, "");
car.back = NO;
logCharToBinary(car.back, "");
car.top = 0x00;
logCharToBinary(car.top, "");
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
輸出
setFront = 00000001, print _direction.bits == 00000001
getFront = 00000001, print _direction.bits == 00000001
setBack = 00000011, print _direction.bits == 00000011
getBack = 00000010, print _direction.bits == 00000011
setTop = 11110011, print _direction.bits == 11110011
getTop = 11110000, print _direction.bits == 11110011
開始清零 先front后back,再清零top
setFront = 11110010, print _direction.bits == 11110010
getFront = 00000000, print _direction.bits == 11110010
setBack = 11110000, print _direction.bits == 11110000
getBack = 00000000, print _direction.bits == 11110000
setTop = 00000000, print _direction.bits == 00000000
getTop = 00000000, print _direction.bits == 00000000
設置讀取
front設置YES ---> 讀取front
setFront = 00000001, print _direction.bits == 00000001
對字節的第0
位賦值為1
,同時不影響其他位
getFront = 00000001
,與其他位無關
back設置YES ---> 讀取back
setBack = 00000011, print _direction.bits == 00000011
對字節的第1
位賦值為1
,同時不影響其他位
getBack = 00000010
,與其他位無關
top設置0xF0 ---> 讀取top
setTop = 11110011, print _direction.bits == 11110011
對字節的第4-7
位賦值為1111
,同時不影響其他位
getTop = 11110000
,與其他位無關
清零讀取
front清零 ---> 讀取front
setFront = 11110010, print _direction.bits == 11110010
,對字節的第0
位賦值為0
,同時不影響其他位
getFront = 00000000
,與其他位無關
back清零 ---> 讀取back
setBack = 11110000, print _direction.bits == 11110000
,對字節的第1
位賦值為0
,同時不影響其他位
setBack = 11110000
,與其他位無關
top清零 --->讀取top
setTop = 00000000, print _direction.bits == 00000000
,對字節的第4-7
位賦值為0000
,同時不影響其他位
getTop = 00000000
,與其他位無關
5.Xcode截圖
6.總結
聯合體位域
,是用一個字節
或者多個字節
其中的二進制位bit
組合到一起表示某種含義