1. 程式人生 > >ios學習路線—Objective-C(裝箱和拆箱)

ios學習路線—Objective-C(裝箱和拆箱)

概述 
從前面的博文我們也可以看到,陣列和字典中只能儲存物件型別,其他基本型別和結構體是沒有辦法放到陣列和字典中的,當然你也是無法給它們傳送訊息的也就是說有些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;
}