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的場合。