概述 從前面的博文我們也可以看到,數組和字典中只能存儲對象類型,其他基本類型和結構體是沒有辦法放到數組和字典中的,當然你也是無法給它們發送消息的也就是說有些NSObject的方法是無法調用的,這個時候通常會用到裝箱boxing和拆箱unboxing。 其實各種高級語言基本上都有裝箱和拆 箱的過程,例 ...
概述
從前面的博文我們也可以看到,數組和字典中只能存儲對象類型,其他基本類型和結構體是沒有辦法放到數組和字典中的,當然你也是無法給它們發送消息的也就是說有些NSObject的方法是無法調用的,這個時候通常會用到裝箱boxing和拆箱unboxing。
其實各種高級語言基本上都有裝箱和拆 箱的過程,例如C#中我們將基本數據類型轉化為Object就是一個裝箱的過程,將這個Object對象轉換為基 本數據類型的過程就是拆箱,而且在C#中裝箱的過程可以自動完成,基本數據類型可以直接賦值給Object 對象。但是在ObjC中裝箱的過程必須手動實現,ObjC不支持自動裝箱。
對象的裝箱和拆箱,在ObjC中我們一般將基本數據類型裝箱成 NSNumber 類型當然它也是 NSObject 的子類,但是 NSNumber 不能對結構體裝箱,調用其對應的方法進行轉換:
+(NSNumber *)numberWithChar:(char)value; +(NSNumber *)numberWithInt:(int)value; +(NSNumber *)numberWithFloat:(float)value; +(NSNumber *)numberWithDouble:(double)value; +(NSNumber *)numberWithBool:(BOOL)value; +(NSNumber *)numberWithInteger:(NSInteger)value;
拆箱的過程就更加簡單了,可以調用如下方法:
-(char)charValue; -(int)intValue; -(float)floatValue; -(double)doubleValue; -(BOOL)boolValue;
示例
#import <Foundation/Foundation.h> /*可以存放基本類型到數組、字典*/ void test1() { //包裝類NSNumber,可以包裝基本類型但是無法包裝結構體類型 NSNumber *number1 = [NSNumber numberWithChar:'a'];//'a'是一個C語言的char類型我們無 法放倒NSArray中,但是我們可以通過NSNumber包裝 NSArray *array1 = [NSArray arrayWithObject:number1]; NSLog(@"%@", array1); /*結果: ( 97 ) */ NSNumber *number2 = [array1 lastObject]; NSLog(@"%@", number2);//返回的不是基本類型,結果:97 char char1 = [number2 charValue];//number轉化為char NSLog(@"%c", char1); //結果:a } int main(int argc, const char *argv[]) { @autoreleasepool { test1(); } return 0; }
結構體的裝箱和拆箱
上面我們看到了基本數據類型的裝箱和拆箱過程,那麼結構體呢? 這個時候我們需要引入另外一個類型NSValue,其實上面的NSNumber就是NSValue的子類,它包裝了一些基本數據類型的常用裝箱、拆箱方法,當要對結構體進行裝箱、拆箱操作我們需要使用NSValue,NSValue可以對任何數據類型進行裝箱、拆箱操作。
事實上對於常用的結構體Foundation已經為我們提供好了具體的裝箱方法:
+(NSValue *)valueWithPoint:(NSPoint)point; +(NSValue *)valueWithSize:(NSSize)size; +(NSValue *)valueWithRect:(NSRect)rect;
對應的拆箱方法:
-(NSPoint)pointValue; -(NSSize)sizeValue; -(NSRect)rectValue;
示例
#import <Foundation/Foundation.h> //NSNumber是NSValue的子類,而NSValue可以包裝任何類型,包括結構體 void test1() { CGPoint point1 = CGPointMake(10, 20); NSValue *value1 = [NSValue valueWithPoint:point1];//對於系統自帶類型一般都有直接的方 法進行包裝 NSArray *array1 = [NSArray arrayWithObject:value1];//放倒數組中 NSLog(@"%@",array1); /*結果: ( "NSPoint: {10, 20}" ) */ NSValue *value2 = [array1 lastObject]; CGPoint point2 = [value2 pointValue];//同樣對於系統自帶的結構體有對應的取值方法(例如 本例pointValue) NSLog(@"x=%f,y=%f", point2.x, point2.y);//結果:x=10.000000,y=20.000000 } int main(int argc, const char *argv[]) { @autoreleasepool { test1(); } return 0; }
自定義的結構體類型的裝箱和拆箱 如果是我們自定義的結構體類型呢,這個時候我們需要使用NSValue如下方法進行裝箱:
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
調用下麵的方法進行拆箱:
-(void)getValue:(void *)value;
示例
#import <Foundation/Foundation.h> typedef struct { int year; int month; int day; } Date; //NSNumber是NSValue的子類,而NSValue可以包裝任何類型,包括結構體 void test1() { //如果我們自己定義的結構體包裝 Date date = {2014, 2, 28}; char *type = @encode(Date); NSValue *value3 = [NSValue value:&date withObjCType:type];//第一參數傳遞結構體地址,第二個參數傳遞類型字元串 NSArray *array2 = [NSArray arrayWithObject:value3]; NSLog(@"%@", array2); /*結果: ( "<de070000 02000000 1c000000>" ) */ Date date2; [value3 getValue:&date2];//取出對應的結構體,註意沒有返回值 //[value3 objCType]//取出包裝內容的類型 NSLog(@"%i,%i,%i",date2.year,date2.month,date2.day); //結果:2014,2,28 } int main(int argc, const char *argv[]) { @autoreleasepool { test1(); } return 0; }