OC学习12——字符串、日期、日历

时间:2022-04-29
本文章向大家介绍OC学习12——字符串、日期、日历,主要内容包括一、字符串、二、日期与时间、三、对象复制、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

  前面主要学习了OC的基础知识,接下来将主要学习Foundation框架的一些常用类的常用方法。Foubdation框架是Cocoa编程、IOS编程的基础框架,包括代表字符串的NSString(代表字符序列不可变的字符串)、NSMutableString(代表字符序列可变的字符串),以及代表日期、时间的NSDate,关于日历的NSCalendar、NSDateComponents等常用类。

一、字符串

1、NSString代表字符序列不可变的字符串,即一旦NSString对象被创建,包含在这个对象中的字符序列就说不可改变的,直至这个对象被销毁。它的功能主要是处理字符串,主要功能如下:

  • 穿件字符串
  • 读取文件或网络URL来初始化字符串
  • 获取字符串长度
  • 获取字符串中的字符或字节
  • 连接字符串
  • 分割字符串
  • 查找字符串内指定的字符和子串
  • 替换字符串
  • 比较字符串
  • 字符串大小比较
  • 字符串的大小写转换
 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         unichar data[6] = {97 , 98 , 99 , 100 , 101, 102};
 7         // 使用Unicode数值数组初始化字符串
 8         NSString* str = [[NSString alloc]
 9             initWithCharacters: data length:6];
10         NSLog(@"%@" , str);
11         char* cstr = "Hello, iOS!";
12         // 将C风格的字符串转换为NSString对象
13         NSString* str2 = [NSString stringWithUTF8String:cstr];
14         NSLog(@"%@" , str2);
15         // 将字符串写入指定文件 
16         [str2 writeToFile:@"myFile.txt"
17             atomically:YES 
18             encoding:NSUTF8StringEncoding
19             error:nil];
20         // 读取文件内容,用文件内容初始化字符串
21         NSString* str3 = [NSString stringWithContentsOfFile:@"NSStringTest.m"
22             encoding:NSUTF8StringEncoding 
23             error:nil];
24         NSLog(@"%@" , str3);
25     }
26 }
 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         NSString* str = @"Hello";
 7         NSString* book = @"《疯狂iOS讲义》";
 8         // 在str后面追加固定的字符串
 9         // 原来字符串对象并不改变,只是将新生成的字符串重新赋给str指针变量
10         str = [str stringByAppendingString:@",iOS!"];
11         NSLog(@"%@" , str);
12         // 获取字符串对应的C风格字符串
13         const char* cstr = [str UTF8String];
14         NSLog(@"获取的C字符串:%s" , cstr);
15         // 在str后面追加带变量的字符串。
16         // 原来字符串对象并不改变,只是将新生成的字符串重新赋给str指针变量
17         str = [str stringByAppendingFormat:@"%@是一本非常不错的图书."
18             , book];
19         NSLog(@"%@" , str);
20         NSLog(@"str的字符个数为:%lu" , [str length]);
21         NSLog(@"str按UTF-8字符集解码后字节数为:%lu" , [str 
22             lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
23         // 获取str的前10个字符组成的字符串
24         NSString* s1 = [str substringToIndex:10];
25         NSLog(@"%@" , s1);
26         // 获取str的从第5个字符开始,与后面字符组成的字符串
27         NSString* s2 = [str substringFromIndex:5];
28         NSLog(@"%@" , s2);    
29         // 获取str从第5个字符开始,到第15个字符组成的字符串
30         NSString* s3 = [str substringWithRange:NSMakeRange(5, 15)];
31         NSLog(@"%@" , s3);
32         // 获取iOS在str中出现位置
33         NSRange pos = [str rangeOfString:@"iOS"];
34         NSLog(@"iOS在str中出现的开始位置:%ld, 长度为:%ld"
35             , pos.location , pos.length);
36         // 将str的所有字符转为大写
37         str = [str uppercaseString];
38         NSLog(@"%@" , str);
39     }
40 }

2、NSMutableString代表字符序列可变的字符串,而且NSMutableString是NSString的子类,因此前面介绍的NSString所包含的方法,NSMutableString都可以直接使用,NSMutableString对象也可以直接当成NSString对象用。此外,NSMutableString还提供了很多可以修改字符串所包含字符序列的方法。

 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         NSString* book = @"《疯狂iOS讲义》";
 7         // 创建一个NSMutableString对象
 8         NSMutableString* str = [NSMutableString 
 9             stringWithString:@"Hello"];
10         // 追加固定字符串
11         // 字符串所包含的字符序列本身发生了改变,因此无需重新赋值
12         [str appendString:@",iOS!"];
13         NSLog(@"%@" , str);
14         // 追加带变量的字符串
15         // 字符串所包含的字符序列本身发生了改变,因此无需重新赋值
16         [str appendFormat:@"%@是一本非常不错的图书." , book];
17         NSLog(@"%@" , str);
18         // 在指定位置插入字符串
19         // 字符串所包含的字符序列本身发生了改变,因此无需重新赋值
20         [str insertString:@"fkit.org" atIndex:6];
21         NSLog(@"%@" , str);
22         // 删除从位置6到位置12的所有字符
23         [str deleteCharactersInRange:NSMakeRange(6, 12)];
24         NSLog(@"%@" , str);
25         // 将从位置6到位置9的字符串替换成Objective-C
26         [str replaceCharactersInRange:NSMakeRange(6, 9)
27             withString:@"Objetive-C"];
28         NSLog(@"%@" , str);
29     }
30 }

二、日期与时间

1、NSDate对象代表日期和时间,OC既提供了类方法来创建NSDate对象,也提供了大量以init开头的方法来初始化NSDate对象。

 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         // 获取代表当前日期、时间的NSDate
 7         NSDate* date1 = [NSDate date];
 8         NSLog(@"%@" , date1);
 9         // 获取从当前时间开始,一天之后的日期
10         NSDate* date2 = [[NSDate alloc]
11             initWithTimeIntervalSinceNow:3600*24];
12         NSLog(@"%@" , date2);
13         // 获取从当前时间开始,3天之前的日期
14         NSDate* date3 = [[NSDate alloc]
15             initWithTimeIntervalSinceNow: -3*3600*24];
16         NSLog(@"%@" , date3);
17         // 获取从1970年1月1日开始,20年之后的日期    
18         NSDate* date4 = [NSDate dateWithTimeIntervalSince1970:
19             3600 * 24 * 366 * 20];
20         NSLog(@"%@" , date4);
21         // 获取系统当前的Locale
22         NSLocale* cn = [NSLocale currentLocale];
23         // 获取NSDate在当前Locale下对应的字符串
24         NSLog(@"%@" , [date1 descriptionWithLocale:cn]);
25         // 获取两个日期之间较早的日期
26         NSDate* earlier = [date1 earlierDate:date2];
27         // 获取两个日期之间较晚的日期
28         NSDate* later = [date1 laterDate:date2];
29         // 比较两个日期,compare:方法返回NSComparisonResult枚举值
30         // 该枚举类型包含NSOrderedAscending、NSOrderedSame和
31         // NSOrderedDescending三个值,正如它们的名字暗示的。
32         // 分别代表调用compare:的日期位于被比较日期之前、相同、之后。
33         switch ([date1 compare:date3])
34         {
35             case NSOrderedAscending:
36                 NSLog(@"date1位于date3之前");
37                 break;
38             case NSOrderedSame:
39                 NSLog(@"date1与date3日期相等");
40                 break;
41             case NSOrderedDescending:
42                 NSLog(@"date1位于date3之后");
43                 break;
44         }
45         // 获取两个时间之间的时间差
46         NSLog(@"date1与date3之间时间差%g秒" 
47             , [date1 timeIntervalSinceDate:date3]);
48         // 获取指定时间与现在的时间差
49         NSLog(@"date2与现在间时间差%g秒" 
50             , [date2 timeIntervalSinceNow]);
51     }
52 }

2、NSDateFormatter代表一个日期格式器,其功能就是完成NSDate和NSString之间的转换。使用NSDateFormatter完成NSDate和NSString之间的转换的步骤如下:

  • 创建一个NSDateFormatter对象
  • 调用NSDateFormatter的setDateStyle:、setTimeStyle:方法设置格式化日期、时间的风格。其中,日期、时间风格有如下几个枚举值:
    • NSDateFormatterNoStyle:不显示日期、时间的风格
    • NSDateFormatterShortStyle:显示“短”的日期、时间的风格
    • NSDateFormatterMediumStyle:显示“中等”的日期、时间的风格
    • NSDateFormatterLongStyle:显示“长”的日期、时间的风格
    • NSDateFormatterFullStyle:显示“完整”的日期、时间的风格
  • 如果打算使用自己的格式模版,则调用NSDateFormatter的setDateFormat:方法设置日期、时间模版即可。

3、如果需要将NSDate转化为NSString,则调用NSDateFormatter的stringFromDate:方法执行格式化即可;如果需要将NSString转化为NSDate,则调用NSDateFormatter的dateFromString:方法执行格式化即可。

 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         // 需要被格式化的时间
 7         // 获取从1970年1月1日开始,20年之后的日期    
 8         NSDate* dt = [NSDate dateWithTimeIntervalSince1970:
 9             3600 * 24 * 366 * 20];
10         // 创建两个NSLocale,分别代表中国、美国
11         NSLocale* locales[] = {
12             [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]
13             , [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]};
14         NSDateFormatter* df[8];
15         //为上面2个NSLocale创建8个DateFormat对象
16         for (int i = 0 ; i < 2 ; i++)
17         {
18             df[i * 4] = [[NSDateFormatter alloc] init];
19             // 设置NSDateFormatter的日期、时间风格
20             [df[i * 4] setDateStyle:NSDateFormatterShortStyle];
21             [df[i * 4] setTimeStyle:NSDateFormatterShortStyle];
22             // 设置NSDateFormatter的NSLocale
23             [df[i * 4] setLocale: locales[i]];
24             df[i * 4 + 1] = [[NSDateFormatter alloc] init];    
25             // 设置NSDateFormatter的日期、时间风格            
26             [df[i * 4 + 1] setDateStyle:NSDateFormatterMediumStyle];
27             [df[i * 4 + 1] setDateStyle:NSDateFormatterMediumStyle];
28             // 设置NSDateFormatter的NSLocale
29             [df[i * 4 + 1] setLocale: locales[i]];
30             df[i * 4 + 2] = [[NSDateFormatter alloc] init];    
31             // 设置NSDateFormatter的日期、时间风格            
32             [df[i * 4 + 2] setDateStyle:NSDateFormatterLongStyle];
33             [df[i * 4 + 2] setTimeStyle:NSDateFormatterLongStyle];
34             // 设置NSDateFormatter的NSLocale
35             [df[i * 4 + 2] setLocale: locales[i]];
36             df[i * 4 + 3] = [[NSDateFormatter alloc] init];    
37             // 设置NSDateFormatter的日期、时间风格            
38             [df[i * 4 + 3] setDateStyle:NSDateFormatterFullStyle];
39             [df[i * 4 + 3] setTimeStyle:NSDateFormatterFullStyle];
40             // 设置NSDateFormatter的NSLocale
41             [df[i * 4 + 3] setLocale: locales[i]];
42         }
43         for (int i = 0 ; i < 2 ; i++)
44         {
45             switch (i)
46             {
47                 case 0:
48                     NSLog(@"-------中国日期格式--------");
49                     break;
50                 case 1:
51                     NSLog(@"-------美国日期格式--------");
52                     break;
53             }
54             NSLog(@"SHORT格式的日期格式:%@"
55                 , [df[i * 4] stringFromDate: dt]);
56             NSLog(@"MEDIUM格式的日期格式:%@"
57                 , [df[i * 4 + 1] stringFromDate: dt]);
58             NSLog(@"LONG格式的日期格式:%@"
59                 , [df[i * 4 + 2] stringFromDate: dt]);
60             NSLog(@"FULL格式的日期格式:%@"
61                 , [df[i * 4 + 3] stringFromDate: dt]);
62         }
63         NSDateFormatter* df2 = [[NSDateFormatter alloc] init];
64         // 设置自定义的格式器模板
65         [df2 setDateFormat:@"公元yyyy年MM月DD日 HH时mm分"];
66         // 执行格式化
67         NSLog(@"%@" , [df2 stringFromDate:dt]);
68         NSString* dateStr = @"2013-03-02";
69         NSDateFormatter* df3 = [[NSDateFormatter alloc] init];
70         // 根据日期字符串的格式设置格式模板    
71         [df3 setDateFormat:@"yyyy-MM-dd"];
72         // 将字符串转换为NSDate对象
73         NSDate* date2 = [df3 dateFromString: dateStr];
74         NSLog(@"%@" , date2);    
75     }
76 }

4、Foundation框架还提供了NSCalendar对象来处理NSDate对象所包含的各个字段的数据,NSCalendar主要包含如下两个方法:

  • (NSDateComponents *) components:fromDate::从NSDate中提取年、月、日、时、分、秒各时间字段信息
  • dateFromComponents:(NSDateComponents *)comps:使用comps对象包含的年、月、日、时、分、秒各时间字段信息来创建NSDate对象

  上面两个方法都用到了NSDateComponents对象,该对象是专门用于封装年、月、日、时、分、秒各时间字段信息的日期组件类。该对象十分简单,它只包含了对year、month、day、hour、minute、second、week、weekday等各字段的setter和getter方法。

  从NSDate中分开获取各时间字段的数值的步骤如下:

  1. 创建NSCalendar对象
  2. 调用NSCalendar的components:fromDate:方法获取数值,返回一个NSDateComponents对象
  3. 调用NSDateComponents的getter方法获取个时间字段的数值

  使用个时间字段的数值来初始化NSDate对象的步骤如下:

  1. 创建NSCalendar对象
  2. 创建一个NSDateComponents对象,并用setter方法对各个字段进行赋值
  3. 调用NSCalendar的dateFromComponents:方法初始化NSDate对象,该方法返回一个NSDate对象
 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         // 获取代表公历的Calendar对象
 7         NSCalendar *gregorian = [[NSCalendar alloc]
 8             initWithCalendarIdentifier:NSGregorianCalendar];
 9         // 获取当前日期 
10         NSDate* dt = [NSDate date];
11         // 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
12         unsigned unitFlags = NSYearCalendarUnit | 
13             NSMonthCalendarUnit |  NSDayCalendarUnit |
14             NSHourCalendarUnit |  NSMinuteCalendarUnit |
15             NSSecondCalendarUnit | NSWeekdayCalendarUnit;
16         // 获取不同时间字段的信息
17         NSDateComponents* comp = [gregorian components: unitFlags 
18             fromDate:dt];
19         // 获取各时间字段的数值
20         NSLog(@"现在是%ld年" , comp.year);
21         NSLog(@"现在是%ld月 " , comp.month);
22         NSLog(@"现在是%ld日" , comp.day);
23         NSLog(@"现在是%ld时" , comp.hour);
24         NSLog(@"现在是%ld分" , comp.minute);
25         NSLog(@"现在是%ld秒" , comp.second);
26         NSLog(@"现在是星期%ld" , comp.weekday);
27         
28         // 再次创建一个NSDateComponents对象
29         NSDateComponents* comp2 = [[NSDateComponents alloc] 
30             init];
31         // 设置各时间字段的数值
32         comp2.year = 2013;
33         comp2.month = 4;
34         comp2.day = 5;
35         comp2.hour = 18;
36         comp2.minute = 34;
37         // 通过NSDateComponents所包含的时间字段的数值来恢复NSDate对象
38         NSDate *date = [gregorian dateFromComponents:comp2];
39         NSLog(@"获取的日期为:%@" , date);
40     }
41 }

三、对象复制

1、NSObject类提供了copy和mutableCopy方法,通过这两个方法即可复制已有对象的副本。

  • copy方法用于复制对象的副本。通常来说,copy方法返回的副本对象总是不可修改的,即使该原始对象是可修改。
  • mutableCopy方法用于复制对象的可变副本,通常来说,mutableCopy方法返回的副本对象总是可修改的(MutableString等),即使该原始对象是不可修改。
  • 无论如何,copy和mutableCopy方法返回的总是原对象的副本,方程序对复制的对象的副本进行修改时,原对象通常不受影响。
 1 #import <Foundation/Foundation.h>
 2 
 3 int main(int argc , char * argv[])
 4 {
 5     @autoreleasepool{
 6         NSMutableString* book = [NSMutableString 
 7             stringWithString:@"疯狂iOS讲义"];
 8         // 复制book字符串的可变副本
 9         NSMutableString* bookCopy = [book mutableCopy];
10         // 对副本修改,对原字符串没有任何影响
11         [bookCopy replaceCharactersInRange:
12             NSMakeRange(2, 3)
13             withString:@"Android"];
14         // 此处看到原字符串的值并没有改变
15         NSLog(@"book的值为:%@" , book);
16         // 字符串副本发生了改变。
17         NSLog(@"bookCopy的值为:%@" , bookCopy);
18         NSString* str = @"fkit";
19         // 复制str(不可变字符串)的可变副本
20         NSMutableString* strCopy = [str mutableCopy]; //①
21         // 向可变字符串后面追加字符串
22         [strCopy appendString:@".org"];
23         NSLog(@"%@" , strCopy);
24         // 调用book(可变字符串)的copy方法,程序返回一个不可修改的副本
25         NSMutableString* bookCopy2 = [book copy]; //②
26         // 由于bookCopy2是不可修改的,因此下面代码将会出现错误
27         [bookCopy2 appendString:@"aa"];    
28     }
29 }

 2、当程序调用对象的copy或mutableCopy方法时,实际上程序底层需要调用copyWithZone:或mutableCopyWithZone:方法来完成实际的复制工作,copy或mutableCopy方法的返回值实际上就是copyWithZone:或mutableCopyWithZone:方法的返回值。而copyWithZone:和mutableCopyWithZone:方法并不是NSObject的方法,而是NSCopy和NSMutableCopy协议中的方法。所以,对于哦我们自定义的类,如果只是简单地继承自NSObject类,在程序中如果直接调用该自定义类的copy或mutableCopy方法时,编译是没有问题的,但是在运行时会出现问题,原因就在于自定义类没有实现NSCopy和NSMutableCopy协议中copyWithZone:和mutableCopyWithZone:方法。所以,如果我们自定义类需要实现copy或mutableCopy方法,则通常需要做以下事情:

  • 让该类实现NSCopy和NSMutableCopy协议
  • 让该类实现copyWithZone:和mutableCopyWithZone:方法
1 #import <Foundation/Foundation.h>
2 
3 @interface FKDog : NSObject <NSCopying>
4 @property (nonatomic , strong) NSMutableString* name;
5 @property (nonatomic , assign) int age;
6 @end
 1 #import "FKDog.h"
 2 
 3 @implementation FKDog
 4 - (id)copyWithZone:(NSZone*)zone
 5 {
 6     NSLog(@"--执行copyWithZone--");
 7     // 使用zone参数创建FKDog对象
 8     FKDog* dog = [[[self class] allocWithZone:zone] init];
 9     dog.name = self.name;
10     dog.age = self.age;
11     return dog;
12 }
13 
14 @end
 1 #import <Foundation/Foundation.h>
 2 #import "FKDog.h"
 3 
 4 int main(int argc , char * argv[])
 5 {
 6     @autoreleasepool{
 7         // 创建一个FKDog对象
 8         FKDog* dog1 = [FKDog new];
 9         dog1.name = [NSMutableString stringWithString:@"旺财"];
10         dog1.age = 20;
11         // 复制副本
12         FKDog* dog2 = [dog1 copy];
13         // 复制对象的可变副本
14 //        FKDog* dog2 = [dog1 mutableCopy];
15         dog2.name = [NSMutableString stringWithString:@"snoopy"];
16         dog2.age = 12;
17         NSLog(@"dog1的名字为:%@" , dog1.name);
18         NSLog(@"dog1的年龄为:%d" , dog1.age);
19         NSLog(@"dog2的名字为:%@" , dog2.name);
20         NSLog(@"dog2的年龄为:%d" , dog2.age);
21     }
22 }

3、深复制和浅复制  Objective-C中的深拷贝和浅拷贝 其实OC中深复制和浅复制的概念与在Java、C++中的概念是一致的。简单来说就是深复制取完全的一个新的副本对象,副本对象与原对象没有任何交集,而浅复制则是原对象与副本对象之间还有交集。所谓交集指的是存在某一个指针变量指向同一个对象的情况。

  • 浅复制:当对象的属性是指针变量时,如果程序只是复制该指针的地址,而不是真正赋值指针所指向的对象,这种方式就被称之为浅复制。
  • 深复制:深复制不仅会赋值对象本身,还会递归赋值每个指针类型的属性,直到两个对象没有任何共用的部分。