OC课程-018: NSDictionary、NSFileManager、单例


一、NSDictionary

185. 整体安排

  • NSDictionary, NSMutableDictionary
  • 集合的内存管理
  • NSFileManager:文件操作类.
  • 常用结构体:CGPoint,CGSize,CGRect.
  • NSValue
  • NSDate 表示时间的类
  • copy 对象拷贝
  • 单例模式

1.将数组中元素的值,保存到磁盘.数据持久化

NSArray *arr = @[@"jack", @"rose", @"lili"];
[arr writeToFile:@"/Users/Apple/Desktop/abc.plist" atomically:NO]; // 存入

NSArray *arr2 = [NSArray arrayWithContentsOfFile:@"/Users/Apple/Desktop/abc.plist"]; // 读取
  1. plist文件,属性列表文件。
    这个文件可以保存数组。把数组中的元素保存在这个文件中。

186. NSDictionary字典。

NSArray,NSMutableArray 是OC中的数组。
存储数据特点:每1个元素紧密相连,并且每1个元素中都是直接存储值的。
缺点:数组元素的下标,不固定。都有可能会发生变化。删除元素,后面的元素会往前顶。
无法通过下标来唯一确定数组中的元素。

希望:有1种存储方式,存储到数组中。可以快速唯一地确定元素。
存储数据时,必须给要存储的数据取一个别名。-----键值对存储。
别名的作用:用来确定别名对应的数据。
要找存储在数组中的数据,使用别名来找, 而下标会变化,但是别名不会。
这种存储数据的方式,叫键值对的存储方式。


187. NSDictionary创建

1. NSDictionary.NSMutableDictionary

都是数组是以键值对的形式存储的。
往这个数组中存储数据的同时,必须要指定这个数据的别名才可以。
要找到元素,也要通过别名来找,而不是通过下标。

2. NSDictionary字典数组

1). 存储数据的原理:
a. 以键值对的形式存储数据.
b. 字典数组一旦创建,其中的元素就无法动态新增或删除.
c. 键:只能是遵守了NSCoping协议的对象,而NSString就是遵守了这个协议.
值:只能是OC对象.

2). 创建字典数组

NSDictionary *dic1 = [NSDictionary new];
NSDictionary *dic2 = [[NSDictionary alloc] init];
NSDictionary *dic3 = [NSDictionary dictionary];
// 创建出来的字典数组中,没任何元素,没有意义。

4). 一般创建方式
+ (instancetype)dictionaryWithObjectsAndKeys:(id)firstObject...

`NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"jack", @"name",nil];`

将字典数组的值键依次写在后面初始化.
5). 简要创建方式
@{键1:值1,键2:值2...}

`NSDictionary *dict = @{@"name":@"rose",@"age":@"18"};`

6). 使用%@可以打印这个数组中所有的元素.
如果字典中没有键名,则返回nil.
1). 别名法
对象名[键名];
NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; dict[@"name"];
2). 方法
- (id)objectForKey:(id)aKey;
NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; [dict objectForKey:@"name"];
3). 取出键值对的个数
@property (readonly)NSUInteger count;
NSDictionary *dict = @{@"name":@"rose",@"age":@"18"}; [dict count];

遍历NSDictionary
1). 字典数组中的数据无法使用下标取
2). 使用for in 循环,遍历出来的是所有数组的键.

    NSDictionary *dict = @{@"name":@"rose",@"age":@"18"};
    for(NSString *key : dict){
        NSLog(@"%@ = %@", key, dict[key]);
    }

3). 使用block遍历

[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop)]{
NSLog(@"%@ = %@", key, obj);
}

4). 数据存储原理
a. 当往字典数组中存储一个键值对的时候,这个键值对应该存储在下标为几的元素中
->> 并不是按照顺序挨个的存储的
->> 存键值对的时候,会根据键值数组的长度做一个哈希算法,算出一个下标,将这个键值存储在该下标处
b. 取值
也是根据键做一个哈希算法,可以算出键值对存储的下标,然后直接找到这个下标的数据取出就可以了.
5). 与NSArray对比
a. NSArray数组的元素,挨个存,按着顺序
b. 存的效率,NSArray要高;
取的时候,单个取NSDictionary相对要快,全部取,NSArray快。

NSMutableDictionary
1). 是NSDictionary的子类
2). 创建可变字典数组

    NSMutableDictionary *dict1 = [NSMutableDictionary new];
    NSMutableDictionary *dict2 = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *dict3 = [NSMutableDictionary dictionary];

这样创建处理的字典长度为0,有意义,可以动态的新增与删除.

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"jack", @"name",nil];
创建的时候并且初始化.

注意:
不可以使用以下代码创建

`NSMutableDictionary *dict = @{@"name":@"rose",@"age":@"18"};`

3). 新增键值对

NSMutableDictionary *dict1 = [NSMutableDictionary new]; [dict1 setObject:@"jack" forKey:@"name"];
如果键名重复,则会覆盖.
4). 删除所有的键值对

  • (void)removeAllObjects: 删除所有的键值对

  • (void)removeObjectForKey:(KeyType)aKey;根据键名删除指定值
    5). 持久化--保存到本地

    写到本地
    [dict writeToFile:@"/Users/Apple/Desktop/1.plist" atomically: NO];
    读到内存
    [NSMutableDictionary dictionaryWithContentsOfFile:@"/Users/Apple/Desktop/1.plist"];
    集合的内存管理
    将对象存储到集合之中,会为这个对象的引用计数器+1,当集合销毁的时候,就会像存储在集合中的所有的对象发送一条release消息.

使用@[]或者@{}创建的集合已经是被autorelease过的了.
直接调用对象方法和类方法创建的对象,也是autorelease过的.

在ARC模式下,集合的元素是一个强类型指针.


二、NSFileManager作用: 创建、删除、赋值、拷贝、移动

NSFileManager是以单例模式创建的
// 单例返回
NSFileManager *fileManager = [NSFileManager defaultManager];
判断
1). 判断指定的文件或者文件夹在磁盘上是否真实的存在

  • (BOOL)fileExistsAtPath:(NSString *)path;
    2). 判断指定的路径是否真实的存储在我们的磁盘上,并且判断这个路径是一个文件夹还是一个路径
  • (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory;
    返回值: 代表这个路径是否真实存在
    参数指针:代表这个路径是否是一个文件夹路径,YES为文件夹路径,NO为文件路径
    3). 判断指定的文件夹或者文件是否可以读取
  • (BOOL)isReadableFileAtPath:(NSString *)path;
    4). 判断指定的文件夹或者文件是否可以写入.
  • (BOOL)isWritableFileAtPath:(NSString *)path;
    5). 判断指定的文件夹或者文件是否可以删除
  • (BOOL)isDeletableFileAtPath:(NSString *)path;

获取信息
1). 获取指定文件或者文件夹的属性信息

  • (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error
    返回是一个字典,如果要拿到特定的信息,通过key
    2). 获取指定目录下的所有文件的目录,是拿到指定目录下的所有文件和目录,所有的后代目录和文件
  • (NSArray *)subpathsAtPath:(NSString *)path;
    3). 获取知道给你目录下的所有的子目录和文件,不保护孙子辈
  • (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error

文件/目录
1). 创建

  • (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr;
    第1个参数: 要创建的文件路径
    第2个参数: 文件的内容,NSData将别的数据转换为二进制数据
    将字符串转换到NSData二进制的方式,调用字符串对象的
  • (NSData *)dataUsingEncoding:(NSStringEncoding)encoding;
    编码参数:NSUTF8StringEncoding
    指定一个编码就可以将字符串转换为二进制数据,存储在NSData对象之中,最后再将这个二进制对象通过这个方法写入,如果想创建一个空文件,第2个参数就给nil。
    第3个参数:指定创建的文件的属性,如果想要使用系统的默认值使用nil
    2). 在指定的目录创建文件夹
  • (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL) createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error;
    第1个参数:路径
    第2个参数:YES,指一路创建,NO不做一路创建
    第3个参数:指定属性,nil为系统默认
    第4个参数:异常信息

3). 拷贝文件

  • (BOOL) copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
    4). 移动文件,剪切,重命名
  • (BOOL) moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
    5). 删除文件
  • (BOOL) removeItemAtPath:(NSString *)path error:(NSError **)error;

注意: 删除的文件不会倒废纸篓,而是直接删除,小心使用


三、常用的结构体
CGPoint
1). Foundation框架中CGPoint定义

    struct CGPoint{
        CGFloat x;
        CGFloat y;
    };
    typedef struct CGPoint CGPoint;
typedef CGPoint NSPoint;

CGPoint类型实际上就是一个double类型.
这个结构体一般情况下来表示坐标,用来表示控件上的位置

声明CGPoint变量并初始化的方式:
a.

CGPoint p1;
p1.x = 20;
p1.y = 30;

b. CGPoint p1 = {20, 30};
c. CGPoint p1 = {.x=20,.y=30};
d. Foundation框架中提供的函数快速创建CGPoint
a). CGPointMake(x,y)
CGPoint p1 = CGPointMake(20,30);
b). NSMakePoint(x,y)
CGPoint p1 = NSMakePoint(20,30);

CGSize
1). 用来描述控件的大小

    struct CGSize{
        CGFloat width;
        CGFloat height;
    };
    typedef struct CGSize CGSize;
typedef CGSize NSSize;

CGSize结构体一般用来表示控件的大小

CGSize声明并初始化的方式
    a. CGSize size;
        size.width = 100;
        size.height = 30;
    b. CGSize size = {100, 30};
    c. CGSize size = {.width = 100, .height = 30};
    d. Foundation框架中提供的函数快速创建CGSize
        a). CGSizeMake(x,y)
            CGSize s1 = CGSizeMake(20,30);
        b). NSSizePoint(x,y)
            NSSize s1 = NSMakeSize(20,30);

CGRect
1). 用来描述控件的大小

    struct CGRect{
        CGPoint origin;
        CGSize size;
    };
    typedef struct CGRect CGRect;
typedef CGRect CGRect;

CGRect结构体一般用来表示控件的大小
CGRect声明并初始化的方式
a. CGRect rect; rect.origin.x = 20; rect.origin.y = 30; rect.size.width = 100; rect.size.height = 30;
b. CGRect rect; rect.origin = (CGPoint){100, 30}; rect.size = (CGSize){100, 30};
d. Foundation框架中提供的函数快速创建CGRect
a). CGRectMake(x,y,width,height)
CGRect s1 = CGRectMake(10,20,20,30);
b). NSRectMake(x,y,width,height)
NSReca s1 = NSRectMake(10,20,20,30);
建议使用CG开头的

四、NSValue

NSRange/CGPoint/CGSize/CGRect都是结构体,无法存储到集合中
先将结构体变量存储到OC对象中,在将OC对象存储到集合中
NSValue类的对象就是用来包装结构体变量的
CGPoint p1 = CGPointMake(10,20);
NSValue *v1 = [NSValue valueWithPoint:p1];
五、NSDate 时间处理

创建NSDate时间

NSDate *date = [NSDate new];
NSDate *date = [NSDate date];

格式化输出日期
yyyy 代表年份
MM 代表月份
dd 代表日
HH 代表24小时制,hh代表12小时制
mm 代表分钟
ss 代表秒

NSDate *date = [NSDate new];
// 1. 先创建日期格式化对象,输出一个指定格式的对象
NSDateFormatter *formatter = [NSDateFormatter new];
// 2. 指定日期格式化对象 转换的格式
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
// 3. 格式化对象按照指定的格式将日期对象转换,转换的时候会自动的转换为当前系统的时区
NSString *str = [formatter stringFromDate:date];

NSString *strDate = @"2011-12-12 12:12:12";
// 1. 先创建一个日期格式化器对象
NSDateFormatter *formatter = [NSDateFormatter new];
// 2. 指定字符串日期的格式
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
// 3. 转换
NSDate *date = [formatter dateFromString:strDate];

计算时间
1). 当前时间之上加上一个时间数

  • (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;
    NSDate *date = [NSDate new];
    NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:60*60*10];

2). 两个时间之差

  • (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;

日历对象

NSDate *date = [NSDate date];
// 1. 创建一个日历对象
NSCalendar *calendar = [NSCalendar currentCalendar];
// 2. 让日历对象从日期对象取出日期的各个部分
NSDateComponents *com = [calendar components: NSCalendarUnitYear fromDate:date];
com.year,com.month,com.day

六、copy

无论是MRC还是ARC下,如果属性的类型是NSString类型的,@property参数使用copy.

copy是个方法
1). 定义在NSObject中,作用:拷贝对象
NSString 调用copy方法,没有产生新对象,而是直接将对象本身的地址返回去,这种拷贝我们叫做浅拷贝.
NSMutableString调用copy对象,产生了一个新对象,这种拷贝叫做深拷贝。拷贝出的对象是一个不可变的字符串对象。
2). mutableCopy拷贝之后是一个NSMutableString,是一个可变对象

字符串拷贝计数器问题
1). 若字符串对象存储在常量区中不允许被回收的,所以引用计数器是一个超大的数,retain和release无效
2). 若字符串存储在对去,这个字符串对象和普通的对象是一样的,引用计数器默认是1.
3). 字符串对象如果是浅拷贝,会将对象的引用计数器加1.
字符串对象如果是深拷贝,原来的对象的引用计数器不变.

@property的copy

copy方法的内部调用了另外一个方法copyWithZone方法,这个方法是定义在NSCoping协议中的,因为我们类没有遵守NSCopingWithZone方法,当我们自定义的类调用copy方法就会报错。

copyWithZone方法实现
--> 如果要做深拷贝,即重新创建一个对象,把对象属性的值复制到新对象中,将新对象返回。
--> 如果做浅拷贝,就直接将对象返回即可.
七、单例模式
一个类的对象,无论在什么时候,什么地方创建,得到的对象都是同一个.最终都会调用该alloc方法创建.
1). alloc方法的内部其实什么都没有做,只是调用了allocWithZone方法.
2). 实际上真正申请空间,创建对象的事情是allocWithZone方法在做.

要实现单例模式--重写+allocWithZone方法

+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static id instance = nil;
    if(nil == instance){
        instance = [super allocWithZone:zone];
    }
    return instance;
}
单例规范

如果类是一个单例模式,要求为类提供一个类方法,来返回这个单例对象。
类方法的名称必须以 shared类名; default类名;

什么时候要把类写成单例的
1). 特点: 一个类的对象,无论在什么时候,什么地方创建,得到的对象都是同一个.最终都会调用该alloc方法创建.存储在单例对象中的数据可以被共享.
单例对象,可以被共享。如果数据需要被整个程序所共享,将数据以属性的方式存储在单例对象中。



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

推荐阅读更多精彩内容

  • 期中考试的几个不等式 1.期中考试的重要性远大于期末考试 作为学期中间阶段的测试,期中测试难度和平时测验难度相当,...
    锋华雪月阅读 77评论 0 0
  • 1、看了几章《金字塔原理》,不是喜欢看的类型的书籍。但也算是一本比较有名气的书了,对于公文写作、沟通表达还是有一些...
    某张三阅读 169评论 1 13
  • 来源:美术与设计学院 班级:22美本二班 姓名:李庭姗 关于志愿支教的体验 参加学校的支教活动,是我期...
    溺_5961阅读 26评论 0 0
  • 炒股日志 2023-05-05 今年旅游出行火爆,在股票市场并没有体现出来,每逢节后板块还会暴跌,那样的话,必须炒...
    道友请留步abc阅读 45评论 0 0
  • 红豆词四首(清)王国维 南国秋深可奈何, 手持红豆几摩挲。 累累本是无情物, 谁把闲愁付与他。 门外青骢郭外舟, ...
    阿意56阅读 110评论 0 2