Foundation框架中最我们经常用的类大致有NSString、NSArray、NSDictionary等等,虽然不需要将每一个类中提供了什么方法都记下来,但是需要做到心中有数,知道Foundation框架提供了什么样的方法,能够达到什么效果,用到的时候直接去API中查找即可,避免因为不知道有这些方法,而走弯路。
NSString是1个数据类型,用来保存OC字符串,NSString的本质是1个类,既然是1个类,所以,最标准的创建NSString对象的方式如下:
NSString *str1 = [NSString new];
NSString *str2 = [[NSString alloc] init];
NSString *str3 = [NSString string];
使用这种方式创建的字符串是1个空的字符@""
。
NSString是OC中最常用的1个类了,所以OC提供了一种更为快速的创建字符串对象的方式:使用前缀@
@"jack";
本质上这是1个NSString对象,这个NSString对象中存储的是"jack"
这个字符串.
NSString *str1 = @"rose";
格式控制符 %p: 打印指针变量的值即地址。 %@: 打印指针指向的对象。
当我们使用@简要的创建字符串对象的时候,也就是使用1个OC字符串常量来初始化字符串指针的时候,这个字符串对象是存储在常量区(数据段) 的。当我们调用NSString的类方法来创建对象的时候.创建的字符串对象是存储在堆区。
NSString *str = @"jack";
NSString *str1 = [NSString new];
NSLog(@"str:%p",str);
NSLog(@"str1:%p",str1);
str/str1地址打印
上图中可以看出,str和str1字符串打印的地址差别很大,因为str在指向常量区地址,而str1指向堆区的地址。
当在内存中创建1个字符串对象以后,这个字符串对象的内容就无法更改,当我们重新为字符串指针初始化值的时候,并不是修改原来的字符串对象,而是重新的创建1个字符串对象并将这个字符串对象的地址重新复制给字符串指针变量。
NSString *str1 = @"jack";
NSLog(@"str1 = %p",str1);
str1 = @"rose";
NSLog(@"str1 = %p",str1);
str1指向的地址改变
从中可以看出,系统在常量区重新创建了字符串"rose",并将"rose"的地址赋值给str1。
当系统准备要在内存中创建字符串对象的时候,会先检查内存中是否有相同内容的字符串对象,如果有,直接指向该内存区域,如果没有才会重新创建。
NSString *str1 = @"jack";
NSLog(@"str1 = %p",str1);
str1 = nil;
NSString *str2 = @"jack";
NSLog(@"str2 = %p",str2);
str1与str2指向相同的地址
注意:存储在常量区的数据不会被回收. 所以存储在常量区的字符串对象也不会被回收.
==
来判断两个OC字符串的内容是否相同, ==
运算符的作用: 比较左右两边的数据是否相同,如果两边都是指针变量,那么比较的是指针变量的值也就是地址。//从指定资源路径读取文本内容.
+ (nullable instancetype)stringWithContentsOfURL:(NSURL *)url encoding:(NSStringEncoding)enc error:(NSError **)error;
//将字符串的内容写入到资源路径中.
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error;
// 如果要向网页或者ftp写内容要有权限.
typedef NS_ENUM(NSInteger, NSComparisonResult)
{
NSOrderedAscending = -1L, //第一个字符串小于传入的字符串
NSOrderedSame, // 相等
NSOrderedDescending // 带个字符串大于传入的字符串
};
NSCaseInsensitiveSearch: 忽略大小写的比较.
NSLiteralSearch: 完全匹配的比较.
typedef struct _NSRange {
NSUInteger location; 代表子串在主串出现的下标.
NSUInteger length; 代表子串在主串中匹配的长度.
} NSRange;
如果没有找到:location 为NSUInteger的最大值, 也就是NSNotFound,length的值为0。所以,判断主字符串中是否包含子字符串,只需要判断返回的NSRange结构体变量的length是否为0就可以。
- (NSString *)substringFromIndex:(NSUInteger)from; 从指定的下标出一直截取到最后.
- (NSString *)substringToIndex:(NSUInteger)to; 从第0个开始截取指定的个数.
- (NSString *)substringWithRange:(NSRange)range; 截取指定的1段范围.
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement
将字符串中第1个参数替换为第2个参数.原来的指针指向字符串的内容是不会变的,新串是以方法的返回值返回的.如果串1中有多个相同的被替换的串,会全部替换。 这个方法还可以做删除串中的一些字符. 原理: 将想要删除的字符替换为@""即可。
@property (readonly) double doubleValue;
@property (readonly) float floatValue;
@property (readonly) int intValue;
@property (readonly) NSInteger integerValue
@property (readonly) long long longLongValue
@property (readonly) BOOL boolValue
转换注意. 从头开始转换,能转换多少就是多少. 到遇到不能转换的时候就停止转换.
str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
@property (readonly, copy) NSString *uppercaseString; // 转换为大写
@property (readonly, copy) NSString *lowercaseString; // 换换为小写
- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set;
[NSCharacterSet characterSetWithCharactersInString:@""]
NSMutableString为可变的字符串,与NSString不同的是,无论NSMutableString修改多少次,对象始终只有一个,每次修改字符串的时候,修改这个对象中的内容即可,不会再重新创建对象。NSMutableString继承自NSString,并对NSString进行了扩展,同样用来存储字符串。
NSMutableString *str1 = [[NSMutableString alloc]init];
NSMutableString *str2 = [NSMutableString string];
注意:不能直接初始化一个字符串常量给NSMutableString
例如:NSMutableString *str = @"xx_cc";
因为@"xx_cc"是一个父类对象,而str指针是一个子类指针,子类指针不能指向父类对象,当调用str的子类独有方法的时候就会出错。
- (void)appendString:(NSString *)aString;
- (void)appendFormat:(NSString *)format, ... ;
+ (instancetype)stringWithString:(NSString *)string;
同时NSMutableString也具备NSString的所有方法。
当我们需要多次使用一个固定的字符串的时候还是尽量使用NSString,因为NSString的恒定性,保证不会创建多余的重复的对象,效率会更高,而当需要大量拼接字符串的时候,需要使用NSMutablString,保证每次拼接都是操作一个对象,不会重复创建多个对象,效率较高。
+ (instancetype)array; // 创建一个没有任何元素的数组
+ (instancetype)arrayWithObject:(ObjectType)anObject; // 创建只有一个OC对象的数组
+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... ; // 使用多个OC对象初始化数组
+ (instancetype)arrayWithArray:(NSArray<ObjectType> *)array;// 使用一个数组初始化另外一个数组
- (instancetype)initWithObjects:(ObjectType)firstObj, ... ;
- (instancetype)initWithArray:(NSArray<ObjectType> *)array;
- (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag; // 不知道YESorNO有什么区别
+ (nullable NSArray<ObjectType> *)arrayWithContentsOfFile:(NSString *)path; // 从文件中读取一个数组数据
+ (nullable NSArray<ObjectType> *)arrayWithContentsOfURL:(NSURL *)url; // 从URL路径中读取一个数组数据
- (nullable NSArray<ObjectType> *)initWithContentsOfFile:(NSString *)path;
- (nullable NSArray<ObjectType> *)initWithContentsOfURL:(NSURL *)url;
需要注意的是NSArray中以nil作为标志表示数组元素传递结束,当设置一个对象为nil,NSArray就会以此为标志结束存储,后面的对象就没有办法存在数组中了。
因此NSArray中不能存储nil,会将nil作为元素结束的标志,并且NSArray中只能存储OC对象,而nil等于0为基本数据类型。
@property (readonly) NSUInteger count; // 获取数组中元素的个数
- (ObjectType)objectAtIndex:(NSUInteger)index; // 获取数组中指定下标的元素的值
- (BOOL)containsObject:(ObjectType)anObject; // 判断数组中是否包含指定元素
- (BOOL)isEqualToArray:(NSArray<ObjectType> *)otherArray; // 判断两个数组是否相同
@property (nullable, nonatomic, readonly) ObjectType firstObject; // 获取数组中第一个元素
@property (nullable, nonatomic, readonly) ObjectType lastObject; // 获取数组中最后一个元素
- (void)makeObjectsPerformSelector:(SEL)aSelector ; // 使数组中所有元素发送消息
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(nullable id)argument // 是数组中所有元素发送带参数的消息
- (NSUInteger)indexOfObject:(ObjectType)anObject; // 查找指定元素第一次出现的下标
- (NSUInteger)indexOfObject:(ObjectType)anObject inRange:(NSRange)range; // 在一定范围内查找指定元素
使用for循环、for in循环均可以遍历数组,for in 循环直接就可以遍历出数组元素的值,要求参数变量必须与数组中元素类型一致,如果数组中元素类型不一致,则可以使用id万能指针。
另外NSArray也提供了在block中遍历数组元素的方法
[arr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// obj:代表便利出来的元素的值 。 idx:代表元素的下标
// 如果希望停止遍历,将stop指针指向的变量赋值为NO即可
}];
NSArry和NSString中分别提供了将数组元素拼接成字符串和将字符串分割成数组的方法 数组提供的拼接字符串方法
// 将数组中的所有元素用separator拼接成一个字符串。
- (NSString *)componentsJoinedByString:(NSString *)separator;
字符串提供的分割字符串组成数组的方法
将字符串以separator分割,每一个字符串成为数组元素存入到数组中
- (NSArray<NSString *> *)componentsSeparatedByString:(NSString *)separator;
NSMutableArray是NSArray的子类,所以NSMutableArray也可以用来存储数据,唯一不同的是NSMutableArray是可变数组,存储在该数组中的元素可以删除,也可以动态增加元素,其他用法均与NSArray相同。
- (void)addObject:(ObjectType)anObject; // 添加元素,默认添加在最后
- (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index; // 往指定位置添加元素
- (void)removeLastObject; // 删除最后一个元素
- (void)removeObjectAtIndex:(NSUInteger)index; // 删除指定元素
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(ObjectType)anObject; // 替换指定位置元素
- (void)addObjectsFromArray:(NSArray<ObjectType> *)otherArray; // 添加另一个数组内的所有元素
- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2; // 交换两个位置的元素
- (void)removeAllObjects; // 删除所有元素
- (void)removeObject:(ObjectType)anObject inRange:(NSRange)range; // 删除指定范围内的指定元素
- (void)removeObject:(ObjectType)anObject; // 删除指定元素
- (void)removeObjectIdenticalTo:(ObjectType)anObject inRange:(NSRange)range; // 在指定范围删除与之相同的元素
- (void)removeObjectIdenticalTo:(ObjectType)anObject; // 删除与之相同的元素
- (void)removeObjectsInArray:(NSArray<ObjectType> *)otherArray; // 删除与另一数组中元素相同的元素
- (void)removeObjectsInRange:(NSRange)range; // 删除指定范围内的元素
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<ObjectType> *)otherArray range:(NSRange)otherRange; // 使用另外一组元素的指定范围替换数组内指定范围元素
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<ObjectType> *)otherArray; // 使用另外一个数组替换数组内指定范围元素
注意:NSMutableArray不能使用语法糖@[]创建,因为语法糖创建的是不可变数组。
有时我们需要将数组的信息(数组的元素的值)保存在沙盒中,进行数据持久化,当使用到的时候在重沙盒中读取 可以使用plist文件保存数组,即将数组的信息存储到plist文件中,就会将数组的所有的元素存储到这个文件中。 NSArray提供了写入数据和读取数据的方法。
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
+ (nullable NSArray<ObjectType> *)arrayWithContentsOfFile:(NSString *)path;
NSDictionary以键值对的形式存储数据,唯一的key对应value,通过key来找到存储在字典中的value。NSDictionary字典一旦创建完毕,其键值对的个数就已经固定,无法删除,新增。
// key = name value = xx_cc ,前面的是value后面的是key
NSDictionary *dict =[NSDictionary dictionaryWithObjectsAndKeys:@"xx_cc",@"name",@"18",@"age", nil];
// 也可以通过快速创建 key:value
NSDictionary *dict2 = @{@"name":@"xx_cc",@"age":@"18"};
@property (readonly) NSUInteger count; // 获取字典中键值对的个数
- (nullable ObjectType)objectForKey:(KeyType)aKey; // 获取键对应的值
@property (readonly, copy) NSArray<KeyType> *allKeys; // 获取所有的key
@property (readonly, copy) NSArray<ObjectType> *allValues; // 获取所有value
除使用for in遍历之外,同样可以使用block进行遍历
[dict2 enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// key 键 ,obj 值
}];
可变字典,相对于字典,可以进行键值对的删除和新增
- (void)removeObjectForKey:(KeyType)aKey; //删除key对应的键值对
- (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey; // 添加键值对
- (void)removeAllObjects; // 删除所有的键值对
- (void)removeObjectsForKeys:(NSArray<KeyType> *)keyArray; // 删除数组中所有key的键值对
NSDictionary也可以将字典数组的信息持久化起来。
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
+ (nullable NSDictionary<KeyType, ObjectType> *)dictionaryWithContentsOfFile:(NSString *)path;
当往字典数组中存储1个键值对的时候,这个键值对并不是按照顺序挨个挨个的存储的,存储键值对的时候,会根据键和数组的长度做1个哈希算法,算出1个下标,将这个键值对存储在该下标处。 取值的时候:也是根据键做1个哈希算法,就可以算出这个键值对存储的下标,然后直接找到这个下标的数据取出就可以了。
因为NSArray和NSDictionary都无法存储基本数据类型,所以NSNumber就是用来将基本数据类型转化为对象的。 基本数据类型存入数组需要先将基本数据类型转化为对象,然后存入数组或者字典中。 基本数据类型转化为NSNumber对象
+ (NSNumber *)numberWithChar:(char)value;
+ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
+ (NSNumber *)numberWithShort:(short)value;
+ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
+ (NSNumber *)numberWithInt:(int)value;
+ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
+ (NSNumber *)numberWithLong:(long)value;
+ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
+ (NSNumber *)numberWithLongLong:(long long)value;
+ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
+ (NSNumber *)numberWithFloat:(float)value;
+ (NSNumber *)numberWithDouble:(double)value;
+ (NSNumber *)numberWithBool:(BOOL)value;
+ (NSNumber *)numberWithInteger:(NSInteger)value;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
也可以使用@直接向基本数据类型封装为对象 @10 代表是1个NSNumber对象,这个对象中包装的是整形的10。如果后面的数据是1个变量,那么这个变量就必须要使用小括弧括起来。
NSNumber对象转化为基本数据类型
@property (readonly) char charValue;
@property (readonly) unsigned char unsignedCharValue;
@property (readonly) short shortValue;
@property (readonly) unsigned short unsignedShortValue;
@property (readonly) int intValue;
@property (readonly) unsigned int unsignedIntValue;
@property (readonly) long longValue;
@property (readonly) unsigned long unsignedLongValue;
@property (readonly) long long longLongValue;
@property (readonly) unsigned long long unsignedLongLongValue;
@property (readonly) float floatValue;
@property (readonly) double doubleValue;
@property (readonly) BOOL boolValue;
@property (readonly) NSInteger integerValue;
@property (readonly) NSUInteger unsignedIntegerValue;
我们常常遇到NSRange、CGPoint、CGSize、CGRect这些结构体,他们的变量没有办法存储到集合之中,因此需要先将这些结构体变量存储到OC对象中,再将OC对象存储到集合之中,NSValue类的对象就是用来包装结构体变量的。
NSValue的使用也非常简单,这里不在赘述了。
日期类也是会经常使用到的,通常需要将服务器返回的时间进行一些处理,或者与当前时间进行计算,然后显示。
获得当前时间,得到的是当前系统的格林威治时间,0时区的时间。
NSDate *date = [NSDate date];
NSLog(@"%@",date);
系统默认的格式 年-月-日 时:分:秒 +时区。 如果想要将时间按照我们既定的格式输出
yyyy: 年份.
MM: 月份.
mm: 分钟.
dd: 天.
hh: 12小时.
HH: 24小时
ss: 秒
formatter.dateFormat = @"yyyy年MM月dd日 HH点mm分ss秒";
NSString *str =[formatter stringFromDate:date];
NSLog(@"str = %@",str);
- (NSString *)stringFromDate:(NSDate *)date; //将日期类型换换为字符串
- (NSDate *)dateFromString:(NSString *)string;//将字符串转换为日期对象.
注意: NSDate取到的时间是格林威治的时间,而NSDateFormatter转换成字符串以后,会自动转换为当前系统的时区的时间。
+ (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
NSDate *d1 =[NSDate dateWithTimeIntervalSinceNow:8*60*60];
- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;
NSDate *date = [NSDate date];
//1.创建1个日历对象. 调用类方法currentCalendar得到1个日历对象.
NSCalendar *calendar = [NSCalendar currentCalendar];
//2.指定日历对象取到日期的对象的那些部分. 是要取那1个时间对象的部分.
// 返回1个日期组件对象.这个对象中就有指定日期的指定部分.
NSDateComponents *com = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:date];
NSLog(@"%ld-%ld-%ld",com.year,com.month,com.day);
文中只是将常用的方法简单列举了一下,这些方法的功能需要做到心中有数,用到的时候去API里面查询即可。也有一些方法虽然不常用,但是用到的时候,这些方法可以很方便的帮我们解决问题,不需要自己去实现走很多弯路。
文中如果有不对的地方欢迎指出。我是xx_cc,一只长大很久但还没有二够的家伙。