Objective-C 学习第十天

简介: 一、NSDictionaryNSArray和NSMutableArray数组存储数据特点:每个元素紧密相连,并且每个元素中都是直接存储的值.缺点:数组元素下标不固定,都有可能发生变化,无法通过下标来唯一确定数组中的元素.

一、NSDictionary

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

  2. NSDictionary(Key-Value存储)与NSMutableDictionary
    1). 它们是数组,以键值对的形式存储数据,通过别名来找数据,类似于java中的Map集合.
    2). 存储数据原理
    a. 以键值对的形式存储数据
    b. 字典数组一旦创建,其中的元素就无法动态的新增和删除
    c. 键: 只能是遵守了NSCoping协议的对象,而NSString遵守了这个协议
    值:只能是OC对象
    3). 创建字典数组

        NSDictionary *dict1 = [NSDictionary new];
        NSDictionary *dict2 = [[NSDictionary alloc] init];
        NSDictionary *dict3 = [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];

  3. 遍历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快。

  4. 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"];
    
  5. 集合的内存管理
    将对象存储到集合之中,会为这个对象的引用计数器+1,当集合销毁的时候,就会像存储在集合中的所有的对象发送一条release消息.

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

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

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

  1. NSFileManager是以单例模式创建的

        // 单例返回
        NSFileManager *fileManager = [NSFileManager defaultManager];
    
  2. 判断
    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;

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

  4. 文件/目录
    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;

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

三、常用的结构体

  1. 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);

  2. 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);
  1. 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

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

五、NSDate 时间处理

  1. 创建NSDate时间
    NSDate *date = [NSDate new];
    NSDate *date = [NSDate date];

  2. 格式化输出日期
    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];
    
  3. 计算时间
    1). 当前时间之上加上一个时间数
    + (instancetype)dateWithTimeIntervalSinceNow:(NSTimeInterval)secs;

     ```
         NSDate *date = [NSDate new];
         NSDate *date1 = [NSDate dateWithTimeIntervalSinceNow:60*60*10];
     ```
    

    2). 两个时间之差
    - (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate;

  4. 日历对象

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

六、copy

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

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

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

  4. @property的copy

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

    • copyWithZone方法实现
      --> 如果要做深拷贝,即重新创建一个对象,把对象属性的值复制到新对象中,将新对象返回。
      --> 如果做浅拷贝,就直接将对象返回即可.

七、单例模式
一个类的对象,无论在什么时候,什么地方创建,得到的对象都是同一个.最终都会调用该alloc方法创建.
1). alloc方法的内部其实什么都没有做,只是调用了allocWithZone方法.
2). 实际上真正申请空间,创建对象的事情是allocWithZone方法在做.

  1. 要实现单例模式--重写+allocWithZone方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static id instance = nil;
    if(nil == instance){
        instance = [super allocWithZone:zone];
    }
    return instance;
}
  1. 单例规范
    如果类是一个单例模式,要求为类提供一个类方法,来返回这个单例对象。

    类方法的名称必须以 shared类名; default类名;

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

目录
相关文章
|
存储 Java 程序员
C++ 开发者快速学习 Objective-C 语言核心语法
本文将讨论 Objective-C 语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。
224 0
|
C++ iOS开发 开发者
C++开发者快速学习Objective-C语言核心语法
  本文将Objective-C讨论了语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。   类并不是特殊的   在Smalltalk中,类是具有一些特性的对象。在Objective-C中也一样。
944 0
|
存储 C语言 iOS开发
Objective-C 学习第一天
一、基础语法 OC相对于C a. 在C的基础上新增了面向对象的语言 b. 将C的复杂、繁琐的语法封装的更为简单 c. OC完全兼容C语言 OC程序的源文件后缀名是.m m代表message 代表OC当中最重要的一个机制 消息机制 C程序的源文件的后缀名.c main函数仍然是OC程序的入口和出口 int类型的返回值代表程序的结束状态 main函数的参数: 仍然可以接收用户在运行程序的时候传递数据给程序, 参数也可以不要 #import指令 1). 以#号开头,是1个预处理指令 2). 作用: 是#include指令的增强版。
815 0
|
存储 iOS开发 C语言
Objective-C 学习第二天
一、 对象在内存中的存储 内存中的五大区域 栈 存储局部变量 堆 程度员手动申请的字节看空间 malloc calloc realloc函数 BSS段 存储未被初始化的全局变量, 静态变量 数据段(常量区) 存储已被初始化的全局、静态变量、常量数据 代码段 存储代码 存储代码程序 类加载 a.
718 0
|
存储 iOS开发
Objective-C 学习第三天
封装 一、 什么是错误 一般情况下,错误是指源代码不符合语法规范,然后编译报错 后果: 程序无法编译 什么是Bug? 程序可以编译、链接、执行,但是程序执行的结果不是我们预想的。
880 0
|
存储 iOS开发
Objective-C 学习第四天
一、 Xcode文档的安装 1). Xcode文档提供了很多框架, 框架当中有很多类和函数, 提供的一些数据类型. 2). Xcode文档需要单独安装.
898 0
|
存储 iOS开发 编译器
Objective-C 学习第五天
一、 创建一个对象,内存是如何分配 1). 子类对象中有自己的属性和所有父类的属性 2). 代码段中每一个类都有一个isa指针,这个指针指向它的父类. 结构体与类 相同点: 都可以将多个数据封装为1个整体 struct Data{ ...
652 0
|
存储 安全 iOS开发
Objective-C 学习第六天
一、 内存管理 内存的作用: 存储数据. 1). 如何将数据存储到内存之中 声明1个变量,将这个数据存储进去 2). 当数据不再被使用的时候,占用的内存空间如何被释放 内存中的五大区域 栈:局部变量,当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收.
947 0
|
存储 对象存储 iOS开发
Objective-C 学习第七天
一、 自动释放池的原理 存入到自动释放池中的对象,在自动释放池销毁的时候,会自动调用储存在该自动释放池中的所有对象的release方法. 可以解决的问题: 将创建的对象,存入到自动释放池之中,就不再需要手动的release这个对象了,因为池子销毁的时候,就会自动的调用池中所有的对象release.
839 0
|
存储 iOS开发
Objective-C 学习第八天
一、延展 延展: Extension 1). 是一个特殊的分类,所以延展也是类的一部分 2). 特殊之处: a. 延展这个特殊的分类没有名字 b. 只有声明没有实现,和本类共享一个实现 延展的语法 语法: @interface 本类名 () @end 没有实现,和本类共享一个实现.
835 0