+ (NSValue *) valueWithBytes: (const void *) value objCType: (const char *) type;
NSValue是用来存储任意数据类型的。传递的参数是你想要包装的数值的地址(如一个NSSize或你自己的struct),通常得到的是你想要存储的变量的地址(在C语言中使用操作符&).你也可以提供一个用来描述这个数据类型的字符串(参数objCType),通常用来说明struct中实体的类型和大小。不需要自己写这个字符串,@encode编译器指令可以接收数据类型的名称并生成合适的字符串。所以按照如下方式把NSRect放入NSArray中。
代码清单显示了如何使用任意结构体创建一个NSValue实例,传入一个结构体实例的地址作为value参数的指针,并通过@encode()指令来查找合适的数据类型。typedef struct { int someMember; float someOtherMember; } MyDataType; MyDataType item; item.someMember = 10; item.someOtherMember = 500.3; NSValue *boxedStruct = [NSValue value:&item withObjCType:@encode(MyDataType)];该技术适用于自定义或者框架提供的任意结构体。比如,可以使用代码清单中的代码来为NSRect和NSSize这两个Foundation结构体编码。NSValue可以用于存储整型、浮点型等,尽管对于这两种类型的值,NSNumber可能是一个更好的选择。还可以在NSValue中存储动态数据的指针。
char *foo = malloc(1024); NSValue *boxedPointer = [NSValue value:&foo withObjCType:@encode(char **)];需要注意的一个要点就是实际要存储的是指针本身而不是数据。因此,需要确保将它存储到NSValue中之后动态分配的数据不会被释放。
//将NSRect放入NSArray中 NSRect rect = NSMakeRect(1, 2, 100, 200); NSValue *rectValue = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)]; [array addObject:rectValue]; // 使用getValue提取数值,传递参数为要存储这个数值的变量的地址 rectValue = [array objectAtIndex: 0]; [rectValue getValue:&rect];在上面的getValue: 例子中,方法名中的get表明我们提供的是一个指针,而指针所指向的空间用来存储该方法生成的数据。
+ (NSValue *) valueWithSIze: (NSSize) size; + (NSValue *) valueWithRect: (NSRect) rect; - (NSPoint) pointValue; - (NSSize) sizeValue; - (NSRect) rectValue; 例子: value = [NSValue valueWithRect: rect]; [array addObject: value]; NSRect anotherRect = [value rectValue];二、NSNull
+ (NSNull *) null; 例如: [contact setObject: [NSNull null] forKey: @"home fax"]; id homefax = [contact objectForKey: @"home fax"]; if (homefax == [NSNull null]{ //... }三、NSNumber包装数字
+ (NSNumber *) numberWithChar: (char) value; + (NSNumber *) numberWithInt: (int) value; + (NSNumber *) numberWithFloat: (float) value; + (NSNumber *) numberWithBool: (BOOL) value;将基本类型数据封装到NSNumber中后,就可以通过下面的实例方法重新获取它:
- (char) charValue; - (int) intValue; - (float) floatValue; - (BOOL) boolValue; - (NSString *) stringValue;
例子: int someNumber = 110; float someFloat = 500.3; NSNumber *theNumber = [NSNumber numberWithInt:someNumber]; NSNumber *theFloat = [NSNumber numberWithFloat:someFloat]; NSNumber *myIntValue = @32; NSNumber *myDoubleValue = @3.22346432; NSNumber *myBoolValue = @YES; NSNumber *myCharValue = @'V'; int n = 5; // Value assigned to primitive type NSNumber *numberObject = [NSNumber numberWithInt:n]; // Value object created from primitive type int y = [numberObject intValue]; // Encapsulated value obtained from value object备注:将一个基本类型的数据包装成对象叫做装箱(boxing),从对象中提取基本类型的数据叫做取消装箱或拆箱(unboxing)。Objective-C不支持自动装箱。
NSArray *employees = ...; [employees makeObjectsPerformSelector:@selector(addToSalary:) withObject:[NSDecimalNumber numberWithFloat:5000.0]]; // addToSalary:的可能实现 -(void)addToSalary:(NSDecimalNumber *)inRaise{ self.salary = [self.salary decimalNumberByAdding:inRaise]; }由于NSDecimalNumber能够存储很大的值(大到38 位 x 10^+/-128)。这样进行一些大数值运算时也很方便,但是直接使用C的标量值会比通过NSDecimalNumber更快,所以需要慎重选择该方法。通常来说,这只在集合中使用。
//建立缓冲区,把字符串添加进去 NSData * data = [NSData dataWithBytes:string length:strlen(string)+1]; char *buf = malloc(1024); NSData *data = [NSData dataWithBytes:buf length:1024];NSData对象最常用于访问存储在文件中或者网络资源中的数据。
int goldOffset = 617; // 文件中偏移617 的位置 int goldLength = 4; // 用于存储gold 值的4 字节空间 NSRange goldRange = NSMakeRange(goldOffset, goldLength); NSMutableData *gameData = [NSMutableData dataWithContentsOfFile:@"..."]; [gameData replaceBytesInRange:goldRange withBytes:newGoldValue]; [gameData writeToFile:@"..." atomically:YES];
可以看出,NSData提供了一个访问原始数据的方便的底层接口。它还提了了一个在集合类内部存储数据的一个很方便的包装器,这与NSNumber和NSValue类似。
//文件管理器使用NSData //NSFileManager可以用来查询单词库目录,创建,重命名,删除目录以及获取、设置文件属性的方法 NSFileManager *fm = [NSFileManager defaultManager]; //创建缓冲区,利用NSFileManager对象来获取文件中的内容,也就是这个文件的属性可修改 NSData *fileData = [fm contentsAtPath:@"/tmp/ver.txt"]; NSLog(@"file data is %@",fileData); //对NSData对象进行判断 if(!fileData) { NSLog(@"file read failed"); }