iOS 相关集合函数的使用

一、结构体

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容