NSValue NSNumber NSData类
步骤1 NSValue
我们先看看NSValue能做什么:
一个NSValue对象是用来存储一个C或者Objective-C数据的简单容器。它可以保存任意类型的数据,比如 int,float,char,当然也可以是指pointer, structure, and object id。NSValue类的目标就是允许以上数据类型的数据结构能够被添加到集合里,例如那些需要其元素是对象的数据结构,如NSArray或者NSSet 的实例。需要注意的是NSValue对象一直是不可枚举的。
1、+ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
创建一个NSValue。
传递的参数是你想要包装的数值的地址(如一个NSSize或你自己的struct),通常得到的是你想要存储的变量的地址(在C语言中使用操作 符&)。你也可以提供一个用来描述这个数据类型的字符串(参数objCType),通常用来说明struct中实体的类型和大小。不需要自己写这 个字符串,@encode编译器指令可以接收数据类型的名称并生成合适的字符串。
2、- (void)getValue:(void *)value(出参);
从NSValue对象中提取数值。
提取的数值,存放在value这个指针所指向的内存块里。
3、Cocoa提供了常用struct数据类型转换成NSValue的便捷方法:
+ (NSValue *)valueWithPoint:(NSPoint)point;
+ (NSValue *)valueWithSize:(NSSize)size;
+ (NSValue *)valueWithRect:(NSRect)rect;
- (NSPoint)pointValue;
- (NSSize)sizeValue;
- (NSRect)rectValue;
NSRect是一个矩形数据种类,NSPoint是起始点,NSSize存储长度和宽度,这些常用的数据种类是C的struct而不是对象。
下边我们通过实验来认识NSValue的使用方式:
#import
int main (int argc, constchar * argv[])
{
@autoreleasepool {
//声明并初始化一个struct NSRectrtc = NSMakeRect(12, 32, 433, 343); //创建一个NSValue: NSValue *value = [NSValue valueWithBytes:&rtc objCType:@encode(NSRect)]; //把value添加到数组中 NSMutableArray *array = [NSMutable ArrayarrayWithCapacity:10]; NSRect rt; [array addObject:value];
的 //从数组中取到NSValue,因为只添加了一个,所以小标是0 NSValue *v = [array objectAtIndex:0]; //从value中取得一个NSRect,虽然返回值是void,但其实是它是利用指针返回值
[v getValue:&rt];
//输出结果 NSLog(@"%f %f %f %f", rt.origin.x, rt.origin.y, rt.size.height, rt.size.width); //用快速枚举遍历array并输出NSValue中struct属性的值 for(NSValue *v in array) { NSRect rt; [v getValue:&rt]; NSLog(@"%f %f %f %f", rt.origin.x, rt.origin.y, rt.size.height, rt.size.width); } /////////////////////便捷的struct转换成NAValue方式//////////////////////// //声明并初始化一个struct NSRect rtc1 = NSMakeRect(100, 200, 300, 400); //创建一个NSValue NSValue *value1 = [NSValue valueWithRect:rtc1]; //把value1添加到数组中 NSMutableArray *array1 = [NSMutable ArrayarrayWithCapacity:10];
[array1 addObject:value1];
NSRect rt1 = [value1 rectValue];
//输出结果
NSLog(@"%f %f %f %f", rt1.origin.x, rt1.origin.y, rt1.size.height, rt1.size.width);
}
} return 0;
注意:在集合中不能存放nil值,因为在NSArray和NSDictionary中nil有特殊的含义。但是在有些时候,确实需要用到这样的空 值,比如在字典中,电话簿中"Zhang San"关键字下有电话号码、家庭住址、Email等等信息,但是现在只知道他的电话号码,这种不知道其他信息
的情况下为了消除一些歧义,有必要将它们设置为空,所以Cocoa提供了NSNull
NSNull只有一个方法:null
[dictionarysetObject:[NSNull null], forKey:"Email"];
if(EmailAdress == [NSNull null])
{
} //to do something
NSNumber 将数据类型数字 封装到对象中
数值对象。
数值标量 -》 对象类型 的互转
基本类型(int,float等)转换为NSNumber NSNumber转换为基本类型(int,float等)
步骤2 NSNumber
NSNumber实际上是NSValue的子类,Cocoa提供了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;
术语:将一个基本类型的数据包装成对象叫做装箱(boxing),从对象中提取基本类型的数据叫做取消装箱或拆箱(unboxing)。Objective-C不支持自动装箱。
下面我们通过实验程序掌握NSNumber的基本用法:
#import
int main (int argc, constchar * argv[])
{
@autoreleasepool { NSNumber *myNumber,*floatNumber,*intNumber,*number; //创建integer类型对象 intNumber = [NSNumber numberWithInteger:123]; NSLog(@"%i",[intNumber integerValue]); //创建long类型对象 myNumber = [NSNumber numberWithLong:0xababab]; NSLog(@"%lx",[myNumber longValue]); //创建char类型对象 myNumber = [NSNumber numberWithChar:‘K‘]; NSLog(@"%c",[myNumber charValue]); //创建float类型对象 floatNumber = [NSNumber numberWithFloat:123.00]; NSLog(@"%f",[floatNumber floatValue]); //创建double类型对象 myNumber = [NSNumber numberWithDouble:12345e+15]; NSLog(@"%lg",[myNumber doubleValue]); // Wrong access here NSLog(@"%i",[myNumber integerValue]); //判断两个对象的值是否相等 if ([intNumber isEqualToNumber:floatNumber] == YES ) { NSLog(@"值相等"); } else {
NSLog(@"值不相等"); }
//比较两个对象的值大小 if ( [intNumber compare:myNumber] == NSOrderedAscending) { NSLog(@"左边的数字小"); } else { } //初始化实例 NSLog(@"左边的数字大");
number = [[NSNumber alloc] initWithInt:1000];
NSLog(@"%i",[number intValue]);
[number release];
}
return 0;
}
注意:
(1)使用程序行myNumber = [NSNumber numberWithDouble: 12345e+15]; 创建double对象,然后尝试(不正确地)使用如下程序行来检索并显示它的值:
NSLog (@”%i”, [myNumber integerValue]);
将得到以下输出:
并且,系统也没有给出出错消息。一般来说,由程序员负责确保正确地进行检索,如果在NSNumber对象中存储了一个值,那么也要用一致的方式进行检索。
(2) NSNumber继承自NSObject,可以使用比较 compare:isEqualToNumber等消息。
(3)此外,还可以使用实例方法初始化NSNumber对象,这些都是以initWith开头,比如initWithInt。
number = [[NSNumber alloc] initWithInt:1000];
注意不能重新初始化前面创建的NSNumber对象的值。例如,不能使用下面的语句设置存储在NSNumber对象myNumber中的整数: [myNumber initWithInt: 1000];
当程序执行时,该条语句将产生一条错误。
步骤3 NSData
Cocoa中使用NSData类型来实现缓冲区,其实你可以把NSData当作JAVA 中的字节数组,用于存储二进制的数据类型,譬如:从网络下载回来的文件等。对于32位应用程序,NSData缓存区最多可以存储2GB的数据。
NSData的创建使用如下的类方法:
+(NSData*)dataWithBytes:(const void*) bytes length:(NSUInteger) length;
第一参数指定你要缓冲的数据的起始位置,也就是指针里存储的首地址,第二个参数指定数据的长度。例如:
#import
int main (int argc, constchar * argv[])
{
@autoreleasepool {
constchar *string="Hi,this is a c string";
//创建NSData对象 NSData *data=[NSData dataWithBytes:string length:strlen(string)+1]; NSLog(@"------%@",data); NSLog(@"length=%d,string=‘%s‘",[data length],[data bytes]); //将数据写入文件中
[data writeToFile:@"/Users/zhangkoumine/Desktop/myfile.txt"
atomically:TRUE];
}
return 0;
}
首先我们定义了一个C语言的字符序列,然后把它的指针、长度赋给了NSData的创建方法。这里需要注意的是由于C语言的字符序列的指针地址本身就 是数组的首地址,所以不需要再加&计算指针的地址了。另外,长度要再加1也是C语言的特性。C语言里的字符串以\0结尾。你会看到Shell窗口 输出一组16进制的数字,也就是缓冲区中存储的内容。NSData是长度不可变的数据缓冲区,还有一个NSMutableData用来存储长度可变的数据 缓冲区。 通常我们在进行文件的读写操作时会用到NSData类,将文件内容读入缓冲区或者将缓冲区的内容写入到一个文件。下面代码展示了如何将文件的内容读入内存 缓冲区,然后再将缓冲区的内容写入到另一个文件中。
例如读取testfile.txt文件中的数据,并将数据写到newfile.txt文件中。
#import
int main (int argc, constchar * argv[])
{
@autoreleasepool { NSFileManager * fm; NSData *fileData; fm = [NSFileManager defaultManager]; //读取文件testfile.txt 使用绝对路径 fileData = [fm contentsAtPath:@"/Users/zhangkoumine/Desktop/testfile.txt"]; if(fileData == nil) { NSLog(@"File read failed!"); return 1;
}
//将数据写到 newfile.txt (相当于拷贝文件)
if([fm createFileAtPath:@"/Users/zhangkoumine/Desktop/newfile.txt"
contents:fileData attributes:nil] == NO)
{
NSLog(@"Couldn‘t create the copy!");
return 2;
}
NSLog(@"File copy was successful!"); //读取拷贝后的文件 newfile.txt中的数据NSLog(@"%@",
[NSString stringWithContentsOfFile:@"/Users/zhangkoumine/Desktop/newfile.txt" encoding:NSUTF8StringEncoding error:nil]);
}
return 0;
}
在实际开发过程中,经常需要将NSData类型与其他类型进行转换。
1, NSData 与 NSString
//NSData --> NSString
NSString *aString = [[NSString alloc] initWithData:adata encoding:NSUTF8StringEncoding]; //NSString --> NSData
NSString *aString = @"1234";
NSData *aData = [aString dataUsingEncoding: NSUTF8StringEncoding];
2, NSData 与 Byte
//NSData --> Byte
NSString *testString = @"1234567890";
NSData *testData = [testString dataUsingEncoding: NSUTF8StringEncoding];
Byte *testByte = (Byte *)[testData bytes];
//Byte --> NSData
Byte byte[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
NSData *adata = [[NSData alloc] initWithBytes:byte length:24];
3, NSData 与 UIImage
//NSData --> UIImage
UIImage *aimage = [UIImage imageWithData: imageData];
//从本地文件沙盒中取图片并转换为NSData
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *name = [NSString stringWithFormat:@"ceshi.png"];
NSString *finalPath = [path stringByAppendingPathComponent:name];
NSData *imageData = [NSData dataWithContentsOfFile: finalPath];
UIImage *aimage = [UIImage imageWithData: imageData];
UIImage-> NSData
NSData *imageData = UIImagePNGRepresentation(aimae);
4, NSData 与 NSMutableData
//NSData --> MSMutableData
NSData *data=[[NSData alloc]init];
NSMutableData *mdata=[[NSMutableData alloc]init];
mdata=[NSData dataWithData:data];
5,NSData合并为一个NSMutableData
- (NSString *)filePathWithName:(NSString *)filename
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:filename];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//音频文件路径
NSString *mp3Path1 = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"mp3"]; NSString *mp3Path2 = [[NSBundle mainBundle] pathForResource:@"2" ofType:@"mp3"]; //音频数据
NSData *sound1Data = [[NSData alloc] initWithContentsOfFile: mp3Path1];
NSData *sound2Data = [[NSData alloc] initWithContentsOfFile: mp3Path2];
//合并音频
NSMutableData *sounds = [NSMutableData alloc];
[sounds appendData:sound1Data];
[sounds appendData:sound2Data];
//保存音频
NSLog(@"data length:%d", [sounds length]);
[sounds writeToFile:[self filePathWithName:@"tmp.mp3"] atomically:YES];
[window makeKeyAndVisible];
return YES;
}