Objective-C的Foundation框架——NSNumber/NSValue/NSNull

NSArray和NSDictionary只能存儲對象,不能直接存儲任何基本類型的數據(如int、float和struct)。

但是我們可以用對象來封裝基本數值,然後再放入NSArray和NSDictionary中。

如果想要使用對象來處理基本類型,就可以使用NSInteger和NSUInteger,這些類型也要針對32爲和64位處理器對數值進行統一。

 

0x01 NSNumber

Cocoa提供了NSNumber類來封裝基本數據類型。

 

使用類方法創建NSNumber對象

可以使用以下類方法來創建新的NSNumber對象(僅舉部分例子):

+ (NSNumber *) numberWithChar: (char) value;
+ (NSNumber *) numberWithInt: (int) value;
+ (NSNumber *) numberWithFloat: (float) value;
+ (NSNumber *) numberWithBool: (BOOL) value;

//示例
int a = 1;
int x = 2;
float f = 3.456;
double d = 7.89;

//int   --->   obj
NSNumber *intObj = [NSNumber numberWithInt:a];
NSMutableArray *array = [NSMutableArray arrayWithObjects:intObj, nil];

//float ---> NSNumber
NSNumber *floatObj = [NSNumber numberWithFloat:f];
[array addObject:floatObj];


//double ---> NSNumber
NSNumber *doubleObj = [NSNumber numberWithDouble:d];
[array addObject:doubleObj];

 

使用字面量語法創建NSNumber對象

NSNumber *number;
number = @'X';         // char
number = @12345;       // integer
number = @12345ul;     // unsigned long
number = @12345ll;     // long long
number = @123.45f;     // float
number = @123.45;      // double
number = @YES;         // BOOL

 

從NSNumber中提取基本類型

將一個基本類型數據封裝到NSNumber中後,我們可以通過一系列方法來重新獲得它:

- (char) charValue;
- (int) intValue;
- (float) floatValue;
- (BOOL) boolValue;
- (NSString *)stringValue;

將創建方法和提取方法搭配在一起使用是可以的,如果用numberWithFloat:方法創建了NSNumber對象,然後用intValue方法來提取數值,NSNumber會對數據進行適當的轉換:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        float f = 3.14;
        
        NSNumber *fnumber = [NSNumber numberWithFloat:f];
        NSLog(@"%@", fnumber);
        
        int i = [fnumber intValue];
        NSLog(@"%d", i);
        
    }
    return 0;
}

//Output:
//2018-07-27 01:20:16.457 test[1896:33403] 3.14
//2018-07-27 01:20:16.458 test[1896:33403] 3
//Program ended with exit code: 0
//

 

0x02 NSValue

前面提到的NSNumber實際上是NSValue的子類,NSValue主要用來封裝自定義的數據結構。

可以是系統框架提供的CGRect/CGPoint/CGSize等數據結構,也可以是自己定義的struct。

 

NSValue提供了封裝方法:

+ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;

同時也提供瞭解封方法:

- (void)getValue:(void *)value;

這裏的方法名中出現了get!

它表明我們提供的是一個指針,而指針所指向的空間則是用來存放該方法生成的數據!

所以,看到這裏應該明白,爲什麼前面的章節說,重寫方法有set而不能有get!

《Objective-C繼承(Inheritance)——重寫方法》

 

下面是示例程序:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        typedef struct testTag
        {
            int  a;
            char *b;
        }TEST_DATA_ST;
        
        TEST_DATA_ST stValue = {0};
        stValue.a = 58;
        stValue.b = "test";
        
        //封裝struct
        NSValue *value = [NSValue valueWithBytes:&stValue objCType:@encode(TEST_DATA_ST)];   
        NSArray *array = [NSArray arrayWithObjects:value, nil];   //封裝成value之後可以裝入NSArray
        
        TEST_DATA_ST testValue = {0};
        [value getValue:&testValue];                              //解封value
        
        NSLog(@"%d, %s", testValue.a, testValue.b);
        
    }
    return 0;
}

//Output:
//2018-07-27 02:08:00.450 test[2311:56190] 58, test
//Program ended with exit code: 0
//

@encode是編譯器指令之一,返回一個給定類型編碼爲一種內部表示的字符串(例如,@encode(int) → i)。

類似於 ANSI C 的 typeof 操作。

蘋果的 Objective-C 運行時庫(runtime)內部利用類型編碼幫助加快消息分發。

 

針對很常見CGRect/CGPoint/CGSize等數據結構,NSValue也提供了封裝好的接口:

//Boxing
+ (NSValue *)valueWithCGPoint:(CGPoint)point;
+ (NSValue *)valueWithCGSize:(CGSize)size;
+ (NSValue *)valueWithCGRect:(CGRect)rect;

//Unboxing
- (CGPoint)CGPointValue;
- (CGSize)CGSizeValue;
- (CGRect)CGRectValue;

 

0x03 NSNull

NSNull是一個類,它只有一個方法:

+ (NSNull *) null;

[NSNull null]用來在NSArray和NSDictionary中加入非nil(表示列表結束)的空值。

[NSNull null]是一個對象,用來表示空,用在不能使用nil的場合。

 

 

發佈了67 篇原創文章 · 獲贊 28 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章