一、结构体
1. NSRange 范围
- 定义
typedef struct _NSRange{
NSUInteger location;// NSUInteger结构体是 unsign long int 类型
NSUInteger length;
} NSRange;
- 创造结构体
NSRange r1 = {2, 4}; // 方法1:不常用
NSRange r2 = {.location = 2, .length = 4}; // 方法2:不常用
NSRange r3 = NSMakeRange(2, 4); // 方法3:Foundation框架自带函数
- NSString 中的 rangeOfString(查找字符串) 方法
作用:查找字符串在本字符串中的范围,返回 NSRange 结构体
注意:如果 查找字符串未找到,返回的 NSRange 结构体 length = 0, location = NSNotFound 「NSNotFound 为枚举类型 为常量整数 -1」
2. NSPoint UI元素的位置
- 定义
typedef struct CGPoint{
// CGFloat结构体 是double类型
CGFloat x; // 在UI界面中 x 向右递增
CGFloat y; // 在UI界面中 y 向下递增
} CGPoint;
typedef CGPoint NSPoint; // 开发用 CGPoint,因为它跨平台
- 创造结构体
CGPoint p1 = NSMakePoint(2, 4); // 方法1:Foundation框架自带函数
NSPoint p2 = CGPointMake(2, 4); // 方法2:开发中常用,CGPoint 和 NSPoint等价
- CGPointZero「常量」等价于 CGPointMake(0, 0);
- <code>bool CGPointEqualToPoint(CGPoint , CGPoint)</code> 比较两个点位置是否相同
3. NSSize UI元素的尺寸
- 定义
typedef struct CGSize{
CGFloat width;// CGFloat结构体 是double类型
CGFloat height;
} CGSize;
typedef CGSize NSSize; // 开发用 CGSize,因为它跨平台
- 创造结构体
CGSize s1 = NSMakeSize(2, 4); // 方法1:Foundation框架自带函数
NSSize s2 = CGSizeMake(2, 4); // 方法2:开发中常用,CGSize 和 NSSize等价
- CGSizeZero「常量」等价于 CGSizeMake(0, 0);
- <code>bool CGSizeEqualToSize(CGSize , CGSize)</code> 比较
4. NSRect 矩形UI元素的 左上角的位置 和 尺寸
- 定义
typedef struct CGRect{
CGPoint origin;
CGSize size;
} CGRect;
- 创造结构体
CGRect rect = { CGPointMake(2, 4), NSMakeSize(2, 4) };
CGRectZero「常量」等价于 CGRectMake(0, 0, 0, 0);
<code>bool CGRectEqualToRect(CGRect , CGRect)</code> 比较「Foundation框架」
<code>bool CGRectCotainsPoint(CGRect, CGPoint)</code>判断 点是否在矩形范围内「CoreGraphics框架」
<code>bool CGRectCotainsRect(CGRect, CGRect)</code>判断 矩形是否在矩形范围内「CoreGraphics框架」
将结构体 转成字符串
NSString *str = NSStringFromCGRect(CGRect rect);
NSLog("%@", str);
打印效果:
<code>{ {0, 0}, {0, 0} }</code>
二、类
1. NSString「不可变字符串」
- 字符串的创建方式
NSString *s1 = @"方法 1";
NSString *s2 = [[NSString alloc] initWithString:@"方法 2"];
NSString *s3 = [[NSString alloc] initWithFormat:@"方法 %d", 3];
NSString *s4 = [[NSString alloc] initWithUTF8String:"方法 4:C字符串 转 OC字符串"];
const char *s = [s4 UTF8String]; // OC字符串 转 C字符串
// 一般都有一个类方法和对象方法配对,方法名为 类名With...
NSString *s5 = [NSString stringWithFormat:@"方法 5"];
NSString *s6=[NSString stringWithContentsOfFile:@"/绝对路径 方法 6" encoding:NSUTF8StringEncoding error:nil];
- 读取文件
// 方法 1:从本地读取
NSString *s1=[[NSString alloc] initWithContentsOfFile:@"/绝对路径" encoding:NSUTF8StringEncoding error:nil];
// 方法 2:从 URL 读取
// URL 格式:协议头://路径「[file://](http://file//) 本地,[ftp://](http://ftp//) , [http://](http:/) 」
NSURL *url = [[NSString alloc] initWithString:@"[file://](http://file//)/绝对路径"]; // 前面"//"是URL格式,后面"/"代表根路径
NSURL *url1 = [NSURL fileURLWithPath:@"/绝对路径"]; // 已经调用的 file方法,无序传入URL的协议头来声明文件类型
NSString *s2 = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
- 写入文件「字符串导出」
// atomically: YES 只有写入完成后才创建文件
// atomically: NO 只要写入就创建文件,不管其是否完整,都创建文件
[@"写入内容对象" writeToFile:@"/路径、创建写入文件名称" atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSURL *url = [[NSString alloc] initWithString:@"[file://](http://file//)/绝对路径"];
[@"写入内容对象" writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
- NSMutableString「继承自NSString,可变字符串」
// 添加到原来字符串后面,返回添加后的新对象「原来字符串不变」
NSString *s = [NSString stringWithFormat:@"可变字符串"];
NSString *s0 = [s appendString:@"添加的字符串"];
// 添加到原来字符串后面「原来字符串变」
NSMutableString *s1 = [NSMutableString stringWithFormat:@"可变字符串"];
[s1 appendString:@"添加的字符串"];
// 删除字符串的一些字符
NSRange range = [s1 rangeOfString:@"加"];
[s1 deleteCharacterInRange: range];
- 字符串比较
NSString *s1 = @"abd";
NSString *s2 = @"abc";
// 比较「内容」是否相同
BOOL result = [s1 isEqualToString: s2];
// 比较「地址」是否相同
result = (s1 == s2);
// 比较「大小」是否相同
// 返回值:
// NSOrderedAscending 前 < 后
// NSOrderedSame 相同
// NSOrderedDescending 前 > 后
result = [s1 compare: s2];
// 比较「大小」是否相同,忽略大小写
result = [s1 caseInsensitiveCompare: s2];
- 字符串搜索
NSString *s = @"[http://www.baidu.com";](http://www.baidu.com";)
// 判断以什么开头
BOOL result = [s hasPrefix: @"[http://](http://"];)"];
// 判断以什么结尾
BOOL result = [s hasSuffix: @".com"];
// 判断是否包涵给定的字符串
// 若包涵,返回给定字符串的 1.起始位置 2.该字符串的长度
NSRange rr = [s rangeOfString: @"bai"]; // 默认:从前往后查找
NSRange rr = [s rangeOfString: @"bai" options:NSBackWardsSearch];
- 字符串截取
NSString *s = @"<head>要截取的字符串</head>";
NSRange range = {6, 7}; // 设置获取字符串范围
NSString *get = [s substringWithRange: range];
// 从 什么地方 开始截取,一直截取到 最后
get = [s subStringFromIndex: 6];
// 从 开头 开始截取,一直截取到 哪个位置
get = [s subStringToIndex: 7];
- 字符串替换
NSString *s = @"ni hao hehe";
// stringByReplacingOccurrencesOfString: 被替换的字符串
// withStirng: 用什么替换
NSString *newStr = [s stringByReplacingOccurrencesOfString: @"hehe" withString: @"haha"];
// 首末位 去除
NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];
newStr = [s stringByTrimmingCharactersInSet: Set]; // 将首末位 去除set对象类型的字符串
- 字符串路径相关方法
NSString *str = @"/h/a/c.c";
// 1.判断是否是绝对路径「判断字符串是否以'/'开头」
BOOL *op = [s isAbsolutePath];
// 2.获取文件路径中的最后一个目录「删除最后一个'/'以及其后面的内容」
NSString *newStr2 = [str lastPathComponent];
// 3.删除文件路径的最后一个目录「获取最后一个'/'的内容」
NSString *newStr3 = [str stringByDeletingLastPathComponent];
// 4.给文件添加一个目录「返回 字符串末尾 + / + 指定内容,若给定内容含有 / 则不会重复添加,若给定内容有重复的 / 则只保留一个」
NSString *newStr4 = [str stringByAppendingPathComponent:@"添加的文件名"];
// 5.获取路径中文件的扩展名「从字符串末尾开始 截取第一个 . 后面的内容」
NSString *newStr5 = [str pathExternsion];
// 6.删除路径中文件的扩展名「从字符串末尾开始 删除第一个 . 后面的内容」
NSString *newStr6 = [str stringByDeletingPathExternsion];
// 7.给文件路径添加一个扩展名
NSString *newStr7 = [str stringByAppendingPathExternsion: @"mm"];
2. NSArray「集合类」
- 存储对象 有序
- 是 OC数组,只能存放OC对象「对象类型不必一致」
- 数组里可以装入 字典类
- 不能存放 nil 值、非OC对象类型「比如:int、struct、enum等」
- NSArray:不可变有序数组
// NSArray 对象创建
NSArray *array0 = [NSArray arrayWithObject:@"创建含有一个对象的字符串数组"];
NSArray *array1 = @["对象1", @"对象2"]; // 编译器会把本句转换为以下一句「编译器特性」,只返回不可变数组 NSArray
NSArray *array2 = [NSArray arrayWithObjects:@"对象1", @"对象2", nil]; // nil是元素结束的标记,必不可少
// NSArray 元素个数
NSLog(@"%ld", array2.count); // 打印array2的数组元素个数,这里 = 2
// NSArray 元素访问
array2[0]; // 编译器自动转为 以下这句
[array2 objectAtIndex:0];
// NSArray 快速遍历 1
// id obj代表数组中的每一个元素
for(id obj in array2){
NSUInteger i = [array2 indexOfObject: obj]; // 找出obj元素在数组中的位置
NSLog(@"%ld - %@", i, obj);
}
// NSArray 快速遍历 2
// 每遍历一个元素就会调用 block,并把 当前元素和索引位置 传给block
// 每次遍历会检测 *stop的值,若为 YES可提前跳出循环
[arrary2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
NSLog(@"%ld - %@", idx, obj);
if(idx==1) *stop = YES;
}];
- NSMutableArray:可变有序数组「继承自 NSArray」
// 数组创建
NSMutableArray *array = [NSMutableArray array];
// 元素添加
[array addObject:@"可添加任何对象,但不能添加 基本数据类型"];
// 删除元素
[array removeAllObjects]; // 删除所有元素
[array removeObject:@"删除指定对象"];
[array removeObjectAtIndex:0]; // 删除下标为0的元素,后面元素自动往前移动
3. NSSet「集合类」
- 存储对象 无序
- 不能存放 nil 值、非OC对象类型「比如:int、struct、enum等」
- NSSet: 不可变无序数组
// 无序数组创建
NSSet *set0 = [NSSet setWithObject:@"创建含有一个对象的字符串数组"];
NSSet *set1 = @["对象1", @"对象2"]; // 编译器会把本句转换为以下一句「编译器特性」
NSSet *set2 = [NSSet setWithObjects:@"对象1", @"对象2", nil]; // nil是元素结束的标记,必不可少
// 随机返回一个对象
NSString *str = [set0 anyObject];
// 删除对象
[set0 removeAllObjects]; // 删除所有元素
[set0 removeObject:@"删除指定对象"];
- NSMutableSet: 可变无序数组「继承自 NSSet」
4. NSDictionary「集合类」
- 不可变、无序集合类
- 集合类型不必一致
- 存储 键值对:key —> value「key值唯一,value值不唯一」
- 如果给出的键 无对应的值,则返回 nil「空」
// 根据键值,创建单元素字典集合对象
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"value" forKey:@"keyName"];
// 创建多元素集合对象 1
NSArray *keys = @[@"keyName",@"address"];
NSArray *objects = @[@"nameValue",@"addressValue"];
NSDictionary *dict = [NSDictionary dictionaryWithObjects:objects forKey:keys];
// 创建多元素集合对象 2
NSDictionary *dict1 = @{@"key1":@"value1", @"key2":@"value2"}; //「编译器特性」只有不可变字典类才会用此方法,自动生成以下代码
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"value1",@"key1", @"value2",@"key2", nil];
// 根据键,获取值
id objValue1 = dict[@"keyName"]; //「编译器特性」自动生成以下代码
id objValue1 = [dict objectForKey:@"keyName"];
// 获取 键值对的 对数
NSLog(@"%ld", dict1.count); // 这里 打印的值是 2
- NSMutableDictionary「可变集合类,继承自NSDictionary」
// 创建 空 可变集合类
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
// 添加键值对
[dict setObject:"value1" forKey:@"keyName1"];
[dict setObject:"value2" forKey:@"keyName1"]; // 当再次给key赋值时,旧值会被新值覆盖
// 移除键值对
[dict removeObjectForKey:@"keyName1"];
// 打印字典类
NSLog(@"%@", dict);
// 打印效果
NSDictionary{
keyName1 = value2;
keyName2 = value2;
}
// 字典遍历 1
NSArray *keys = [dict allKeys]; // 取出字典类所有的 key值作为一个有序的数组
for(int i=0; i<dict.count; i++){
NSArray *key = keys[i];
NSArray *obj = dict[key];
NSLog(@"%@ = %@", key, obj);
}
// 字典遍历 2
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
NSLog(@"%@ = %@", key, obj); // *stop = YES; 时提前停止
}];
// 数组类嵌套字典类
NSArray *persons = @[
@{@"key1":@"value1", @"key2":@"value2"}, //字典类 0
@{@"key3":@"value3", @"key4":@"value4"} //字典类 1
];
NSLog(@"%@", persons[0]); // 输出 字典类 0
NSLog(@"%@", persons[0][@"key1"]); // 输出 value1
5. 基本数据类型 转换为 OC类
- 将 基本数据类型 转换为 NSNumber对象「in、char、float、double、short、long、long long」
NSNumber *n = @10; //「编译器特性」自动生成以下代码
NSNumber *n = [NSNumber numberWithInt:10]; // 此外还有:@YES、@'A'、@5.21
// 将 变量 包装成 NSNumber对象
int age = 20;
NSNumber *n1 = @(age); //「编译器特性」自动生成以下代码
NSNumber *n1 = [NSNumber numberWithInt:age];
// C语言字符串转换为 OC字符串
char *c = "init_a_C_string";
NSString *oc = @(c);
- 将 NSNumber对象 转换为 基本数据类型
<code>int i = [n intValue];</code> - NSNumber因为继承了 NSValue 所以能包装基本数据类型为对象
NSValue 可以将 结构体 转换 为对象
CGPoint *p = CGPointMake(10, 10);
NSValue *v = [NSValue valueWithPoint: p]; // 将结构体 包装成 NSValue对象
NSArray *a = @[v]; // 将包装后的对象放入数组集合中使用
6. NSDate
// 创建时间对象
NSDate *date = [NSDate date];
// 打印时间「打印的为0时区的时间,不是本时区的时间」
NSLog(@"%@", date);
- NSDateFormatter 日期格式化类
// 日期 -> 字符串
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// y=年、M=月、d=日、m=分、s=秒、H=时「24小时制」、h=时「12小时制」
formatter.datFormat = @"yyyy-MM-dd HH:mm:ss"; // 设定日期格式
NSString *str = [formatter stringFromDate: date]; // 将 日期 转为 字符串
// 字符串 -> 日期
NSString *time = @"2016-02-13 23:49";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.datFormat = @"yyyy-MM-dd HH:mm"; // 设定日期格式
NSDate *date = [formatter dateFromString: time]; // 将 字符串 转为 日期
7. NSCalendar
NSDate *now = [NSDate date];
// 创建日历对象「非单例对象」
NSCanlendar *calendar1 = [NSCanlendar currentCanlendar];
// 利用日历类,从当前 Date对象中 单独获取 年月日时分秒
// components:获取多个枚举类型参数
NSCanlendatUnit type = NSCanlendatUnitYear | NSCanlendatUnitMonth; // 通过 | 链接多个枚举值
NSDateComponents *cmps = [calendar1 components:type fromDate now];
NSLog(@"Year = %ld", cmps.year);
// 比较两个时间的差值
// 设置过去的时间
NSString *ss =@"2016-2-17 4:27:26 +0000";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormatter = @"yyyy-MM-dd hh:mm:ss Z";
NSDate *date = [formatter dateFromString: ss];
NSDateComponents *cmp1 = [calendar components:type fromDate:date toDate:now options:0];
8. 集合对象的内存管理
- 若将对象添加到数组中,则数组会对对象进行 一次 retain
- 数组对象释放,会给数组所有对象发送一条 release 消息
- 数组移除对象,会给移除的对象发送一条 release 消息
9. copy
定义:利用一个源 文件/对象,产生一个副本 文件/对象
特点:修改副本对象不会引起原对象的改变
方法:
- copy:创建不可变副本(NSString、NSArray、NSDictionary)
不会生成新对象,copy的对象是原来的那一个对象「浅拷贝:指针拷贝」
因为都不可变,所以为了优化内存,不会生成新对象
使用copy功能的前提:遵守NSCopying协议,实现 copyWithZone:方法 - MAC平台下,不可变副本使用copy方法,不会 对原来对象进行 一次retain
- IOS平台下,不可变副本使用copy方法,会 对原来对象进行 一次retain
// s 为 不可变字符串
NSString *s = @"Hello";
NSString *s1 = [s copy]; //不会产生新对象「都是不可变,不用另外开辟空间复制,浅复制」
NSLog(@"s的地址:%p s1的地址:%p", s, s1);
- mutableCopy:创建可变副本(NSMutableString、NSMutableArray、NSMutableDictionary)
使用 mutableCopy 功能前提:遵守NSMutableCopying协议,实现 mutableCopyWithZone: 方法
会生成新对象,mutableCopy 的对象是一个新对象「深拷贝:内容拷贝」 - 由于生成新对象,在任何平台下都 不会 对原来对象进行 一次 retain
只会对新对象进行 一次 retain
NSMutableString *s2 = @"Hey";
NSMutableString *s3 = [s2 copy]; // 不会产生新对象「浅复制」
NSMutableString *s4 = [s2 mutableCopy]; // 会产生新对象「深复制」
NSLog(@"s2的地址:%p s3的地址:%p s4的地址:%p",s2, s3, s4);
- copy block 之后引发循环引用
如果对象中 block 又用到了对象本身,那么为了避免内存泄露,应该将对象修饰为 __block
typedef myBlock
@interface Person:Object
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy)
@end
int main(){
__block Person *p = [[Person alloc] init]; // [p retainCount] == 1
p.name = @"原来对象";
p.pBlock = ^(){
NSLog(@"name = %@", p.name); // [p retainCount] == 2
}
p.pBlock;
[p release]; // [p retainCount] == 1
return 0;
}
自定义类实现 copy 操作
- 遵守 NSCopying 协议
- 实现 copyWithZone:该方法返回对象的副本
创建一个新对象,并设置该对象数据与现有对象一致,返回该对象 - zone:表示 分配对象需要的内存空间,避免出现堆内存碎片而使用「古老的技术,系统指定,几乎可以忽略」
// Student 父类
@implememt Person
- (id) copyWithZone:(NSZone *)zone{
// 1.创建一个新对象
Person *p = [[[self class] allocWithZone:zone] init];
// 2. 设置当前对象值为新的对象
p.age =_age;
p.name = _name;
// 3. 返回新对象
return p;
}
@end
// Person 子类
@implememt Student
// 想要子类copy保留子类的属性,必须重写copyWithZone:方法
- (id) copyWithZone:(NSZone *)zone{
// 1. 使用父类函数,创建副本,设置值
id obj = [super copyWithZone: zone];
// 2. 设置子类特有的值
[obj setHeight:_height];
// 3. 返回新对象
return p;
}
@end