Foundation框架中常用的类有字符串、集合、字典等,这里介绍字符串NSString。本文分别介绍了NSString的创建、从文件里读取NSString字符串、通过函数改变外部的NSString变量的值、NSString字符串的导出、NSString的常用方法等5个部分。
1.NSString的创建:
#pragma mark NSString的创建 void stringCreate() { // char *s = "A String!"; // C语言中的字符串 // 这种方式创建出来的字符串是不需要释放的 NSString *str1 = @"A String!"; NSString *str2 = [[NSString alloc] init]; str2 = @"A String!"; [str2 release]; NSString *str3 = [[NSString alloc] initWithString:@"A String!"]; [str3 release]; // 不需要管理内存 str3 = [NSString stringWithString:@"A String!"]; NSString *str4 = [[NSString alloc] initWithUTF8String:"A String!"]; [str4 release]; str4 = [NSString stringWithUTF8String:"A String!"]; NSString *str5 = [[NSString alloc] initWithFormat:@"My age is %i and height is %.2f", 19, 1.55f];//(图1) // 这句代码放在中间会造成2个错误: // 1.前面创建的字符串没有被释放 // 2.后面创建的字符串会释放过度,造成野指针错误 // str5 = [NSString stringWithFormat:@"My age is %i and height is %.2f", 19, 1.55f];//(图2、3) NSLog(@"str5:%@", str5); [str5 release]; str5 = [NSString stringWithFormat:@"My age is %i and height is %.2f", 19, 1.55f]; }
(图1) (图2) (图3)
野指针的产生:通过“[[NSString alloc] initWithFormat:@"My age is %i and height is %.2f", 19, 1.55f];”(动态创建)这句创建的对象是需要手动释放内存的,如果在还没有手动释放之前又通过静态方法“str5 = [NSString stringWithFormat:@"My age is %i and height is %.2f", 19, 1.55f];”(静态创建)给str5对象赋值,那么str5将指向新的一块内存,而原来的那块内存没有对象指向它了,但是也没有被释放,就成了野指针。动态方式创建一般都有对应的静态方法创建。
2.从文件里读取NSString字符串
void stringCreate2() { // 从文件中读取文本 NSString *path = @"/Users/apple/Desktop/test.txt"; // 这个方法已经过期,不能解析中文 // NSString *str1 = [NSString stringWithContentsOfFile:path]; // 定义一个NSError变量 NSError *error; // 指定字符串编码为UTF-8: NSUTF8StringEncoding NSString *str1 = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; //最后的一个参数不能传error,一定要传error的地址,它是指向error这个指针的指针 if (error == nil) { // 没有错误信息 NSLog(@"读取文件成功:%@", str1); } else { NSLog(@"读取文件失败:%@", error); } NSURL *url = [NSURL URLWithString:@"file:///Users/apple/Desktop/test.txt"]; NSString *str2 = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@", str2); NSURL *url2 = [NSURL URLWithString:@"http://www.baidu.com"]; NSString *str3 = [NSString stringWithContentsOfURL:url2 encoding:NSUTF8StringEncoding error:nil]; NSLog(@"%@", str3); }
3.通过函数改变外部的NSString变量的值
先看一种情况:
void test(NSString *str){ str = @"123"; } int main(int argc, const char *argv[]) { autoreleasepool{ NSString *s = @"456"; test(s); NSLog(@"%@", s); } return 0; }
运行结果为:456。s的值并没有改变,分析如下:
指针变量s起初指向456(图1),当调用test函数时,传入参数s,函数会开辟一块存储空间存储指针变量str,指针变量是存储地址的,参数s将其存储的地址赋值给str(值传递)(图2),因此str存储的地址也指向了456这个对象,“str = @"123";”执行后,系统又开辟了一块存储空间存储123,接着让str指向这个对象(图3)。而s的值根本没有变,它一直都指向456。所以,对于一个函数,如果只是把一个指针传进去,外面的值是不会变的。
(图1) (图2) (图3)
若要通过函数改变外面指针指向的值,需要用到指针的指针,也就是把外面指针的地址传进去。
void test(NSString **str) { *str = @"123"; // s = @"123"; }
int main(int argc, const char *argv[])
{
autoreleasepool{
NSString *s = @"456";
test(&s);
NSLog(@"%@", s);
}
return 0;
}
指针变量是这样的,那对于一般类型的变量呢?看下面的例子:
void test2(int p){ p = 9; } int main(int argc, const char * argv[]) { @autoreleasepool { int a = 10; test2(a); NSLog(@"%i", a); } return 0; }
运行结果:10;
void test2(int *p) { *p = 9; } int main(int argc, const char * argv[]) { @autoreleasepool { int a = 10; test2(&a); NSLog(@"%i", a); } return 0; }
运行结果:9。
效果是一样的。再次说明,如果要设计一个方法,改变外面传进来的参数,那应该将外面这个参数的地址传递给函数。
4.NSString字符串的导出
#pragma mark 字符串的导出 void stringExport() { NSString *str = @"123456我是字符串!!!!"; // 如果文件不存在,会自动创建文件 // 如果文件夹不存在,会直接报错 NSString *path = @"/Users/apple/Desktop/abc.txt"; NSError *error; // 编码指定错误也会报错 // YES代表要进行原子性操作,也就是会创建一个中间的临时文件 [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error]; if (error) { // [error localizedDescription]会返回主要的错误信息 NSLog(@"写入失败:%@", [error localizedDescription]); } else { NSLog(@"写入成功"); } }
原子性与非原子性的区别:
若写入文件为原子性操作,则在写入内容之前会创建一个临时文件,先将内容写入临时文件,待内容完好无损地写入临时文件后,再将临时文件里的内容移到目标文件中,中途如果出错,临时文件出问题,不会影响到目标文件;非原子性操作直接将内容写入目标文件,一旦中途出错,可能造成目标文件里只有部分内容传入的情况。
5.NSString的常用方法
1 #pragma mark 字符串的大小写处理 2 void caseTest() { 3 NSString *str = @"GuangDong"; 4 // 转成大写 5 NSLog(@"大写:%@", [str uppercaseString]); 6 // 转成小写 7 NSLog(@"小写:%@", [str lowercaseString]); 8 // 首字母变大写,其他字母变小写 9 NSLog(@"首字母变大写:%@", [@"aGE" capitalizedString]); 10 } 11 12 #pragma mark 字符串的比较 13 void compare() { 14 // 检测字符串的内容是否相同 15 BOOL result = [@"abc" isEqualToString:@"abc"]; 16 NSLog(@"%i", result); 17 18 // NSOrderedAscending 右边的字符串比左边大 19 // NSOrderedSame 两个字符串的内容相同 20 // NSOrderedDescending 左边的字符串比右边的大 21 NSComparisonResult result2 = [@"abc" compare:@"Abc"]; 22 if (result2 == NSOrderedSame) { 23 NSLog(@"两个字符串的内容相同"); 24 } else if (result2 == NSOrderedAscending) { 25 NSLog(@"右边 > 左边"); 26 } else if (result2 == NSOrderedDescending) { 27 NSLog(@"右边 < 左边"); 28 } 29 } 30 31 #pragma mark 字符串的搜索 32 void search() { 33 NSString *str = @"123456456.txt"; 34 35 NSLog(@"是否以22开头:%i", [str hasPrefix:@"22"]); 36 NSLog(@"是否以txt结尾:%i", [str hasSuffix:@"txt"]); 37 38 // 搜索字符串 39 NSRange range = [str rangeOfString:@"456"]; 40 // range.length == 0 41 if (range.location == NSNotFound) { 42 NSLog(@"不能找到"); 43 } else { 44 NSLog(@"找到的范围是:%@", NSStringFromRange(range)); 45 } 46 47 // 从尾部开始搜索字符串 48 range = [str rangeOfString:@"456" options:NSBackwardsSearch]; 49 NSLog(@"%@", NSStringFromRange(range)); 50 51 // 指定范围进行搜索 52 // [str rangeOfString:@"456" options:NSBackwardsSearch range:<#(NSRange)#>]; 53 } 54 55 #pragma mark 字符串的截取 56 void subString() { 57 NSString *str = @"123456"; 58 59 // 从索引3开始截取到尾部(包括3) 60 NSLog(@"%@", [str substringFromIndex:3]); 61 62 // 从头部开始截取到索引3之前(不包括3) 63 NSLog(@"%@", [str substringToIndex:3]); 64 65 // 指定范围进行截取 66 NSRange range = NSMakeRange(2, 3); 67 NSLog(@"%@", [str substringWithRange:range]); 68 69 NSString *str2 = @"a-b-c-d-5"; 70 NSArray *array = [str2 componentsSeparatedByString:@"-"]; 71 NSLog(@"%@", array); 72 73 NSString *str3 = [array objectAtIndex:0]; 74 NSLog(@"%@", str3); 75 } 76 77 #pragma mark 与路径相关 78 void pathTest() { 79 // 快速创建一个自动释放的数组 80 NSMutableArray *components = [NSMutableArray array]; 81 [components addObject:@"Users"]; 82 [components addObject:@"MJ"]; 83 [components addObject:@"Desktop"]; 84 // 将数组中的所有字符串拼接成一个路径 85 NSString *path = [NSString pathWithComponents:components]; 86 NSLog(@"%@", path); 87 88 // 将路径分解成一个数组 89 NSArray *cmps = [path pathComponents]; 90 NSLog(@"%@", cmps); 91 92 // path是一个字符串常量,是不可变的 93 path = @"/users/mj/test"; 94 // 判断是够为绝对路径(依据是前面有无/) 95 NSLog(@"%i", [path isAbsolutePath]); 96 NSLog(@"最后一个目录:%@", [path lastPathComponent]); 97 // 删除最后一个目录 98 NSLog(@"%@", [path stringByDeletingLastPathComponent]); 99 // 在最后面拼接一个目录 100 NSLog(@"%@", [path stringByAppendingPathComponent:@"abc"]); 101 } 102 103 #pragma mark 拓展名处理 104 void extension() { 105 NSString *str = @"/User/MJ/test.txt"; 106 107 NSLog(@"拓展名:%@", [str pathExtension]); 108 // 删除拓展名 109 NSLog(@"%@", [str stringByDeletingPathExtension]); 110 // 添加拓展名 111 NSLog(@"%@", [@"abc" stringByAppendingPathExtension:@"mp3"]); 112 } 113 114 #pragma mark 其他用法 115 void other() { 116 NSString *str = @"12"; 117 int a = [str intValue]; 118 NSLog(@"%i", a); 119 120 // 计算字数,不是计算字符数 121 NSLog(@"length=%zi", [@"我是字符串123" length]); 122 123 // 取出对应的字符 124 unichar c = [@"abc" characterAtIndex:0]; 125 NSLog(@"%c", c); 126 127 // 返回C语言中的字符串 128 const char *s = [@"abc" UTF8String]; 129 NSLog(@"%s", s); 130 }