菜单

整理归纳,字典NSDictionary的深复制

2019年8月19日 - 4166m金沙

iOS/Objective-C开发 字典NSDictionary的深复制(使用category),iosnsdictionary

目标:把NSDictionary对象转换成NSMutableDictionary对象,对象内容是字符串数组,需要实现完全复制(深复制)。 

如果调用NSDictionary的mutableCopy方法,可以得到一个NSMutableDictionary对象,但这只是浅复制,如果我们修改NSDictionary中数组内的值(当然,数组必须是NSMutableArray),会发现,NSMutableDictionary对象内数组的值也跟着更改了。我们需要增加一个mutableDeepCopy方法来实现深复制,在该方法中,循环复制每一个元素。 

要实现这一功能,有两种方法,一是继承,二是使用category。category与继承的区别在于,使用category并不是新建一个类,而是在原类的基础上增加一些方法(使用的时候还是用原类名),这样,我们就不需要修改已经在其他源文件中写好的类名,只需要导入h头文件,再把复制方法修改成我们新增的方法即可。 

一、新建Objective-C category文件,我这Category填MutableDeepCopy,Category
on填NSDictionary,所以生成的文件是NSDictionary+MutableDeepCopy.h和NSDictionary+MutableDeepCopy.m,生成的文件名很容易理解。 

二、两文件源代码: 

NSDictionary+MutableDeepCopy.h 

C++代码  图片 1

  1. #import <Foundation/Foundation.h>  
  2.    
  3. @interface NSDictionary (MutableDeepCopy)  
  4. -(NSMutableDictionary *)mutableDeepCopy;  
  5. //增加mutableDeepCopy方法  
  6. @end  

NSDictionary+MutableDeepCopy.m: 

C++代码  图片 2

  1. #import “NSDictionary+MutableDeepCopy.h”  
  2.    
  3. @implementation NSDictionary (MutableDeepCopy)  
  4. -(NSMutableDictionary *)mutableDeepCopy  
  5. {  
  6.     NSMutableDictionary *dict=[[NSMutableDictionary alloc] initWithCapacity:[self count]];  
  7.     //新建一个NSMutableDictionary对象,大小为原NSDictionary对象的大小  
  8.     NSArray *keys=[self allKeys];  
  9.     for(id key in keys)  
  10.     {//循环读取复制每一个元素  
  11.         id value=[self objectForKey:key];  
  12.         id copyValue;  
  13.         if ([value respondsToSelector:@selector(mutableDeepCopy)]) {  
  14.             //如果key对应的元素可以响应mutableDeepCopy方法(还是NSDictionary),调用mutableDeepCopy方法复制  
  15.             copyValue=[value mutableDeepCopy];  
  16.         }else if([value respondsToSelector:@selector(mutableCopy)])  
  17.         {  
  18.             copyValue=[value mutableCopy];  
  19.         }  
  20.         if(copyValue==nil)  
  21.             copyValue=[value copy];  
  22.         [dict setObject:copyValue forKey:key];  
  23.    
  24.     }  
  25.     return dict;  
  26. }  
  27. @end  

 

 

测试: 

 

 

C++代码  图片 3

  1. #import <Foundation/Foundation.h>  
  2. #import “NSDictionary+MutableDeepCopy.h”  
  3. //导入头文件  
  4. int main (int argc, const char * argv[])  
  5. {  
  6.    
  7.     @autoreleasepool {  
  8.         NSMutableArray *arr1=[[NSMutableArray alloc] initWithObjects:@”aa”,@”bb”,@”cc”, nil];  
  9.         NSDictionary *dict1=[[NSDictionary alloc] initWithObjectsAndKeys:arr1,@”arr1″, nil];  
  10.         NSLog(@”%@”,dict1);  
  11.         NSMutableDictionary *dict2=[dict1 mutableCopy];  
  12.         //浅复制  
  13.         NSMutableDictionary *dict3=[dict1 mutableDeepCopy];  
  14.         //深复制  
  15.         [arr1 addObject:@”dd”];  
  16.         NSLog(@”%@”,dict2);  
  17.         NSLog(@”%@”,dict3);  
  18.    
  19.     }  
  20.     return 0;  
  21. }  

目标:把NSDictionary对象转换成NSMutableDictionary对象,对象内容是字符串数组,需要实现完全复制(深复制)。 

1. 熟悉Git的基本流程

  1. git clone
  2. git add -A
  3. git commit -m ” “
  4. git push
  5. git pull

  6. OC(Objective – C)中的类和对象

  7. 熟悉使用编程过程中常用的快捷键 并熟练使用 提高代码速度.

  8. 类和对象
  9. 类: 一个具有相同特征和行为的事物的抽象集合.
  10. 对象: 类的实例也成为类的实现.
  11. OOP(面向对象编程) OOD(面向对象设计)
  12. 面向对象的三大特性: 封装 继承 多态 (都是为了提高代码的复用)
  13. 创建一个Person类 包含name,age和sex三个实例变量

    {
    @public
    NSString *_name;
    @private
    NSInteger _age;
    @protected
    NSString *_sex;
    }

@public (公有的, 本类,子类和其他类都可以使用)
@protected (受保护的,本类和子类可以使用)
@private (私有的, 只有本类才可以使用)
- (void)setName:(NSString *)name; // setter方法(赋值方法) - (NSString *)name; // getter方法(取值方法) - (void)sleep:(NSInteger)time; // 实例方法的声明: 返回值类型 + 方法名 + 参数列表
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age; // 初始化方法
+ (instancetype)personWithName:(NSString *)name age:(NSInteger)age; // 遍历构造器

Objective C中怎把一个基本数据类型( int[],char[] )放入NSDictionary这样的集合中,

首先,NSDictionary这样的集合只能存放objective-c对象,所以需要先将基础数据类型封装。
苹果将int等基础数据类型封装成一个叫NSNumber的类,先将你需要的基础数据封装成NSNumber然后就可以加入到NSDictionary中了。
NSString是字符串类,将CString封装到NSString对象里就可以放入字典中了。当然,放入NSNumber也是可以的,不过NSString要方便许多。
具体代码如下:
NSNumber *num = [NSNumber numberWithInt:1];
NSString *string = [NSString stringWithCString:”Sample”
encoding:NSUTF8StringEncoding];
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:num,
@”num”, string, @”string”, nil];
 

如果调用NSDictionary的mutableCopy方法,可以得到一个NSMutableDictionary对象,但这只是浅复制,如果我们修改NSDictionary中数组内的值(当然,数组必须是NSMutableArray),会发现,NSMutableDictionary对象内数组的值也跟着更改了。我们需要增加一个mutableDeepCopy方法来实现深复制,在该方法中,循环复制每一个元素。 

3.字符串和数值

  1. NSString 的方法
    /** 初始化(init) /
    NSString
    str = [[NSString alloc] init];
    / 便利构造器(string) /
    NSString
    str1 = [NSString string];
    /
    获取字符串长度(length) /
    NSUInteger length = str.length;
    /
    * 获取字符串中字符(character) /
    /
    * 字符串是否相等(equal) /
    [str isEqualToString:str1];
    /
    * 获取子串(sub) /
    /
    * 拼接字符串(append) */
    [str stringByAppendingString:@”dsdsddf”];
    [str stringByAppendingFormat:@”kfkdjf%@”, str];

     NSString *pathStr = @"/users/local/bin";
     // 有返回值的需要接收一下
     pathStr = [pathStr stringByAppendingPathComponent:@"name.plist"];
     NSLog(@"%@", pathStr);
      /** 替换字符串(replace) */
     //        str stringByReplacingCharactersInRange:<#(NSRange)#> withString:<#(nonnull NSString *)#>
     /** 字符串对象转化为int类型(int) */
     [str intValue];
     /** 字符串对象转化为其他数据类型, 例如double, float, BOOL等. */
     [str doubleValue];
     [str floatValue];
     [str boolValue];
     /** 字符串全部大写(uppercase) */
     [str uppercaseString];
     /** 字符串全部小写(lowercase) */
     [str lowercaseString];
     /** 字符串首字母大写(capitalized) */
     [str capitalizedString];
     /** 是否以指定字符串为前缀(prefix) */
     BOOL a = [str hasPrefix:@"sd"];
     /** 是否以指定字符串为后缀(suffix) */
     BOOL b = [str hasSuffix:@"dsd"];
    
  2. 数组
    数组: 分为可变数组 NSMutableArray 与 不可变数组 NSArray
    数组中只能存放对象类型元素
    数组主要是有序存放元素的集合类型 并且可以通过下标取值
    不可变数组只能取值 可变数组可以増 删 改
    2.1 初始化一个不可变数组
    1> initWithObjects + 任意对象类型
    有序填入每个元素 初始化结束以nil为判别标准 遇到nil 就表示数组结束
    当数组里存在空元素时 如果用初始化 或者 构造器的话 程序运行不会报错
    我们可能会不在意 可是此时数组中元素已经丢失 而字面量方式写的
    数组可以使程序crash 能很直接的告诉我们 数组中存在空值
    所以一般在创建数组时用字面量方法 我们也能知道
    在数组中元素不能有空值
    NSArray *array = [[NSArray alloc] initWithObjects: @”123″,
    @”234″, @”345″, @”456″, nil];
    2> 构造器方法
    NSArray *arr = [NSArray arrayWithObjects:@”123″, @”234″, @”345″,
    @”456″, nil];
    3> 字面量 同 NSString @”” NSNumber @()
    NSArray *myArray = @[@”123″, @”234″, @”345″, @”456″];
    2.2 数组的取值
    1> count 取数组元素的个数
    NSLog(@”%ld”, array.count);
    2> 通过下标取出数组元素
    NSString *numStr = [array objectAtIndex:2];
    3> array[0] 语法糖 取值
    NSString *numStr1 = array[0];
    4> 根据值取下标
    NSUInteger indexObject = [array indexOfObject:@”234″];
    NSLog(@”%ld”, indexObject);
    5> 用下面的方式来取数组中的元素 可以避免数组为空时
    不必要的crash
    [array lastObject];
    [array firstObject];
    2.3 初始化可变数组(不推荐使用字面量)
    NSMutableArray *array = [NSMutableArray array];
    1> 数组中添加元素
    [array addObject:@”777″];
    2> 插入
    [array insertObject:@”hahah” atIndex:1];
    3> 移除
    [array removeObject:@”777″];
    [array removeAllObjects];
    4> 替换
    [array replaceObjectAtIndex:0 withObject:@”zhaohao”];

    可变数组和不可变数组的区别

    1. 可变指的是本身可变 不可变要是想改变的话 就要用一个数组来接收
    2. 可变 继承于不可变 也就是说可变的数组是不可变的子类
  3. 字典
    存储键值对(key – value)的集合类型
    字典存储数据是无序的
    通过key值存储 查找value
    1> 初始化
    先value 后key
    字典中只能存放对象类型
    如果有数字 将数字转化为NSNumber类型
    3.1 不可变字典
    1> 不可变字典初始化
    NSDictionary *dic = [[NSDictionary alloc]
    initWithObjectsAndKeys:@”tantan”, @”name”, [NSNumber
    numberWithInt:18], @”age”, @”tantan”, @”firstName”, nil];
    2> 不可变字典遍历构造器
    NSDictionary *dic1 = [NSDictionary
    dictionaryWithObjectsAndKeys:@”jiajia”, @”name”, [NSNumber
    numberWithInt:20], @”age”, nil];
    3> 字面量 先 key 后value (数字为NSNumber类型)
    NSDictionary *dic2 = @{@”name”: @”zhengyu”, @”age”: @(20), @”sex”:
    @”man”};
    4> 取值 通过key值取对应的value
    NSString *str = [dic2 objectForKey:@”name”];
    NSLog(@”%@”, str);
    5> 获取所有key值
    NSArray *keyArr = [dic2 allKeys];
    NSLog(@”%@”, keyArr);
    6> 获取所有value
    NSArray *valueArr = [dic2 allValues];
    NSLog(@”%@”, valueArr);
    7> count 与key 或 value的个数相同
    NSUInteger count = [dic2 count];
    NSLog(@”%ld”, count);
    8> 通过一个字典的key 取另一个字典中对应value数组
    NSArray *allValueArr = [dic objectsForKeys:dic2.allKeys
    notFoundMarker:[NSNumber class]];
    NSLog(@”%@”, allValueArr);
    9> 有可能两个相同的value 对应的key不同
    用下面的方法就可以查找出所有不同的key 将这些key 放到一个数组里
    NSArray *keyArray = [dic allKeysForObject:@”tantan”];
    NSLog(@”%@”, keyArray);
    10> dic[@”name”]; (语法糖) dic[key]
    NSLog(@”%@”, dic1[@”name”]);
    3.2 可变字典
    1> 可变字典初始化方式 (不推荐使用字面量)
    NSMutableDictionary *mutDic = [NSMutableDictionary
    dictionaryWithObjectsAndKeys:@”yuhan”, @”name”, @”man”, @”sex”,
    @”18″, @”age”, nil];
    NSMutableDictionary *mutDic1 = [[NSMutableDictionary alloc]
    init];
    NSMutableDictionary *mutDic = [@{} mutableCopy]; (不推荐)
    2> 取值与不可变 相同
    3> 可变字典可以进行増 删 改 操作
    4>. 给字典添加键值对 用setObject: forKey: 如果新增加的key存在
    会将之前的value覆盖 如果key不存在 会使字典增加一个键值对1
    [mutDic setObject:@”yuhan” forKey:@”name”];
    [mutDic1 setObject:@”man” forKey:@”sex”];
    NSLog(@”%@, %@”, mutDic, mutDic1);
    5>. 删除字典中的键值对
    [mutDic removeObjectForKey:@”name”];
    NSLog(@”%@”, mutDic);
    [mutDic removeAllObjects];
    NSLog(@”%@”, mutDic);
    6>. 语法糖 赋值 与 字典添加键值对作用一样 可以向字典里添加键值对
    也可以从字典里取 值
    mutDic[@”where”] = @”huludao”;
    mutDic[@”birth”] = @”1993″;
    mutDic[@”study”] = @”college”;
    NSLog(@”%@”, mutDic);
    NSLog(@”%@”, mutDic[@”where”]);

  4. 遍历和排序
    4.1 遍历
    4.1.1 for循环遍历数组
    将数组倒序输出 存放在一个可变数组中
    首先创建一个不可变数组 让后用可变数组接收
    NSArray *arr = @[@”伟仔”, @”阿美”, @”飞哥”, @”糖糖”, @”瑞瑞”];
    NSMutableArray *mutArr = [NSMutableArray array];
    for (NSInteger i = arr.count – 1; i >= 0; i–) {
    [mutArr addObject:arr[i]];
    }
    NSLog(@”%@”, mutArr);
    4.1.2 for循环遍历字典
    定义一个字典 遍历输出 name sex age
    NSDictionary *dic = @{@”name”: @”陈冠希”, @”sex”: @”man”, @”age”:
    @”35″};
    NSArray *keyArr = dic.allKeys;
    for (NSInteger i = 0; i < keyArr.count; i++) {
    NSString *key = keyArr[i];
    NSString *value = [dic objectForKey:key];
    NSLog(@”%@ = %@”, key, value);
    4.1.3 枚举器遍历数组
    NSEnumerator *stringArrayEnumerator = [arr objectEnumerator];
    id value = nil;
    while ((value = [stringArrayEnumerator nextObject])) {
    NSLog(@”%@”, value);
    }
    // 倒序输出
    NSEnumerator *rever = [arr reverseObjectEnumerator];
    id value1 = nil;
    while ((value1 = [rever nextObject])) {
    NSLog(@”%@”, value1);
    }
    4.1.4 枚举器遍历字典
    字典 枚举器 默认打印字典的value 也可以打印所有的key值 无序的
    NSEnumerator *dicEnumerator = [dic.allKeys objectEnumerator];
    id value2 = nil;
    while (value2 = [dicEnumerator nextObject]) {
    // NSArray *allKey = [dic allKeysForObject:value2]; 取key
    NSLog(@”%@”, value2);
    }
    4.1.5 枚举器遍历集合
    NSSet *set = [NSSet setWithObjects:@”q”, @”w”, @”e”, @”r”,
    nil];
    NSEnumerator *setEnu = [set objectEnumerator];
    id setValue = nil;
    while (setValue = [setEnu nextObject]) {
    NSLog(@”%@”, setValue);
    }
    4.1.6 快速枚举(for…in…) 遍历数组
    NSString *newStr = [NSString string];
    for (NSString *string in arr) {
    NSLog(@”%@”, string);
    newStr = [newStr stringByAppendingString:string];
    }
    NSLog(@”%@”, newStr);
    4.1.7 快速枚举遍历字典
    for (NSString *dicStr in dic) {
    NSLog(@”%@”, dicStr);
    NSLog(@”%@”, [dic objectForKey:dicStr]);
    }
    4.1.8 集合 快速遍历
    for (NSString *setStr in set) {
    NSLog(@”%@”, setStr);
    }
    4.2 排序
    参数1 key: 排序条件 参数2 acending YES(升序) / NO(降序)
    数组有排序的方法
    NSArray *numArr = @[@1, @7, @5, @4];
    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
    initWithKey:@”self” ascending:YES];
    numArr = [numArr sortedArrayUsingDescriptors:@[sort]];
    NSLog(@”num: %@”, numArr);
    可变数组与不可变数组 排序使用的方法不同
    NSMutableArray *numMutArr = [NSMutableArray arrayWithObjects:@”1″,
    @”5″, @”6″, @”2″, nil];
    NSSortDescriptor *mutSort = [[NSSortDescriptor alloc]
    initWithKey:@”self” ascending:YES];
    [numMutArr sortUsingDescriptors:@[mutSort]];
    NSLog(@”%@”, numMutArr);

  5. 内存管理

  6. 内存溢出 没存用尽 导致crash

  7. 野指针 指针指向被释放的地方 过度释放
    内存方式
    垃圾回收机制 只有mac有
    MRC 手动管理引用计数
    ARC 自动管理引用计数 ARC基于MRC
    看到 retain alloc copy 引用计数加1 需要进行内存管理
    NSObject *objc = [[NSObject alloc] init];
    [objc retain];
    // 需要两次释放
    [objc release];
    [objc release];
    release autorelease 会对引用计数减1
    当对象的引用计数为0时 系统会调用相应的dealloc方法
    ARC
    语义特性: strong(强引用 引用计数加1) weak(应用于简单对象类型 弱引用
    对象被释放时 对象会自动置空) retain(强引用 引用计数加1)
    copy(吧对象拷贝一份 原来的引用计数不变 新对象的引用计数加1)
    assign(应用于简单数据类型 不会产生引用计数)
    协议
  8. 声明协议
  9. 签订协议
  10. 实现协议方法
    注意事项:
    在ARC工程下使用MRC的文件(三方) -fno-objc-arc
    在MRC工程下使用ARC的文件 -fobjc-arc
    需要加在 build phases下的编译source下

  11. 类的扩展

  12. 类目
    category(类别 类目 分类)
    创建category (通过Object – C创建会产生两个文件 文件名: 类 +
    category名 .h / .m)
    例: 创建一个类目, 给NSString添加方法 获取字符串首字母并将其大写
    .h文件

#import <Foundation/Foundation.h>

 @interface NSString (Uper)
 - (void)getStr:(NSString *)str;
 - (NSString *)getFirstChar;
 @end

.m文件
#import “NSString+Uper.h”

   @implementation NSString (Uper)

   - (void)getStr:(NSString *)str {
   NSString *str1 = [str uppercaseString];
   NSLog(@"%@", [str1 substringToIndex:1]);
   }

   - (NSString *)getFirstChar {
   NSString *first = [self substringWithRange:NSMakeRange(0,  1)];
   return first.uppercaseString;
   }

   @end

main.m
#import <Foundation/Foundation.h>
#import “NSString+Uper.h”

   int main(int argc, const char * argv[]) {

   // 获取字符串首字母 并将其大写
   NSString *str = @"zhaohao";
   [str getStr:str];

   NSString *first = [str getFirstChar];
   NSLog(@"%@", first);

   return 0;
   }
  1. 延展(Extension) 一般定义在.m文件里
    例:
    .h文件中声明
    #import <Foundation/Foundation.h>

     @interface Lovers : NSObject
    
     - (void)getLoverLife;
     @end
    

.m文件
#import “Lovers.h”
// 延展的声明
@interface Lovers ()
// 使用延展 可以保证.h的简洁 外界要用到的属性 / 方法才在.h中声明
// 延展中 主要实现属性 / 方法
@property (nonatomic, copy) NSString *cloth;
// 声明方法

  1. 代理delegate模式
    Student.h
    #import <Foundation/Foundation.h>
    // 第一步 规定了协议内容
    @protocol GetMacBook <NSObject>

    • (NSString *)buyMacBook:(NSString *)money; // 默认必须实 现
      @optional // 可选的实现方法
    • (void)drawBill;
      @end

      @interface Student : NSObject
      // 第二步 设定委托方
      // 委托方的写法
      @property (nonatomic, weak) id delegate;
      // 什么时候触发代理

      • (void)seeWeChat;

        @end

Student.m
#import “Student.h”

    @implementation Student
    // 第三步 让代理人执行方法
    - (void)seeWeChat {
    // 代理人可能没有实现协议方法
    // 判断代理人是否存在 判断代理人能否响应 对应的协议方法 当两者同时满足 执行
    if (self.delegate != nil && [self.delegate respondsToSelector:@selector(buyMacBook:)]) {
    NSString *mac = [self.delegate buyMacBook:@"14000"];
    NSLog(@"%@", mac);
    }
   }
   @end

BuyPerson.h
#import <Foundation/Foundation.h>
#import “Student.h”
// 第四步 签订协议
@interface BuyPerson : NSObject <GetMacBook> // 签协议

    @end

BuyPerson.m
#import “BuyPerson.h”

    @implementation BuyPerson
    // 实现协议方法
    - (NSString *)buyMacBook:(NSString *)money {
    NSLog(@"%@", money);
    return @"mac";
    }
    @end

main.m
Student *stu = [[Student alloc] init];
BuyPerson *per = [[BuyPerson alloc] init];
// 设定代理人
stu.delegate = per;
[stu seeWeChat]

objective-c的NSDictionary, 为何这段输出是null

你太粗心了,ObjectsAndKeys:,前边是值,后边的是key,找不到你的:@”john”的
 

字典NSDictionary的深复制(使用category),iosnsdictionary
目标:把NSDictionary对象转换成NSMutableDictionary对象,对象内容是字符串数…

要实现这一功能,有两种方法,一是继承,二是使用category。category与继承的区别在于,使用category并不是新建一个类,而是在原类的基础上增加一些方法(使用的时候还是用原类名),这样,我们就不需要修改已经在其他源文件中写好的类名,只需要导入h头文件,再把复制方法修改成我们新增的方法即可。 

6. iOS新特性

  1. nonnull nullable null_resettable修饰属性
    Person.h
    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN

     @interface Persson : NSObject
     // Nullability(判断为不为空的能力) 是在编译层次上加了一些改  动 (只能作用于对象类型)
     // nonnull声明的属性不能为空 (setter和getter方法)
     // @property (nonatomic, nonnull, assign) NSInteger age;   (错的)
     @property (nonatomic, nonnull, copy) NSString *name;
     @property (nonatomic, copy) NSString * __nonnull size;
     // nullable声明属性可以为空 (setter和getter方法)
     @property (nonatomic, nullable, copy) NSString *sex;
     @property (nonatomic, copy) NSString * __nullable study;
     // UIViewController中的view属性
     @property (null_resettable, nonatomic, strong) NSArray *friends;
    
     @property (nonatomic, strong) NSDictionary *dic;
     // NS_ASSUME_NONNULL_BEGIN     NS_ASSUME_NONNULL_END
     // 一般应用于不头文件.h 一般将属性包含起来 默认 nonnull 如  果是其他修饰要加 例如 nullable null_resettable 要写
    
     NS_ASSUME_NONNULL_END
     @end
    

Person.m
#import “Persson.h”

    @implementation Persson

    // null_resettable 声明属性时会阿生冲突 需要重写setter方法处理掉为空的情况
    - (void)setFriends:(NSArray *)friends {
    if (friends == nil) {
    friends = [NSArray array];
    return;
    }
    _friends = friends;
    }
   @end

main.m
Persson *per1 = [[Persson alloc] init];
// nonnull 修饰属性 对应的getter和setter方法
per1.name = nil; // 不能为空
per1.name = @”zhoahao”;
per1.size = nil; // 不能为空
// nullable 修饰属性 对应的getter和setter方法
// [per1 setSex:<#(NSString * _Nullable)#>];
per1.study = nil;
// null_resettable
// [per1 setFriends:<#(NSArray * _Nullable)#>] set
方法可以为空值
// [per1 friends]; getter 方法是nonnull
per1.friends = nil;

  1. 泛型
    带泛型的容器 (规定了容器中所存储的类型 数组中添加其他类型会有警告
    数组中取出的类型不再是id类型 泛型会改变类的一些方法
    与之声明的方法相同) (例如: 声明一个可变数组内部存放的都是字符串
    不能放其他类型)
    NSMutableArray *array1 = [NSMutableArray
    arrayWithObjects:@”zhaohao”, nil];
    NSMutableArray<NSString *> *array = [NSMutableArray
    arrayWithObjects:@”123″, nil];
    // array1.lastObject. id 类型 没有length属性
    // array.lastObject.length NSString类型 有length
    [array addObject:@” “];
    // [array addObject:@20];
    // [array addObject:per1];
    协变性 与 逆变性
    #import <Foundation/Foundation.h>
    // 自定义泛型声明方式
    // @interface 类名<泛型名> : 父类
    // 自定义泛型 声明后 泛型名 可以应用在属性 方法中
    // 泛型名等效于 类型修饰 (例: NSString *)
    @interface Truck<__contravariant ObjectType> : NSObject
    @property (nonatomic, strong) ObjectType firstObject;

    • (void)addObject:(ObjectType)object;

      • (id)anyObject;

        @end
        #import “Truck.h”

        @implementation Truck

        • (void)addObject:(id)object {
          }

        • (id)anyObject {
          return nil;
          }

        // 方法的返回值 是一个数组 / 可变数组

      • (__kindof NSArray *)returnArray { // 加上kindof 返回的是这 个类及这个类的子类
        // return @[];
        return [NSMutableArray array];
        }
        @end

        main.m
        Truck oneTruck = nil;
        Truck> truck1 = nil;
        Truck> *truck2 = nil;
        // 大类型(任意类型) 可赋值给任意类型 任意类型也可赋值给大类型
        oneTruck = truck1;
        oneTruck = truck2;
        truck1 = oneTruck;
        truck2 = oneTruck;
        // covariant 协变性 子类在给父类赋值时 自动强转
        truck1 = truck2;
        //
        contravariant 逆变性 父类给子类赋值 自动强转
        truck2 = truck1;

  2. __kindOf
    #import <Foundation/Foundation.h>
    @interface Truck<__contravariant ObjectType> : NSObject
    @property (nonatomic, strong) ObjectType firstObject;

    • (void)addObject:(ObjectType)object;

      • (id)anyObject;

      • (__kindof NSArray *)returnArray;
        @end

        #import “Truck.h”

        @implementation Truck

      • (void)addObject:(id)object {
        }

      • (id)anyObject {
        return nil;
        }

        // 方法的返回值 是一个数组 / 可变数组

      • (__kindof NSArray *)returnArray { // 加上kindof 返回的是这 个类及这个类的子类
        // return @[];
        return [NSMutableArray array];
        }
        @end

        main.m
        Truck truckKindOf = [[Truck alloc] init];
        // NSMutableArray
        arr = (NSMutableArray )[truckKindOf returnArray]; // 强转
        NSArray
        arr1 = [truckKindOf returnArray];

  3. UIView UIWindow

7.1 程序的组成结构

  1. main.m (没有他, 程序不能正常运行)

  2. AppDelegate (程序的执行者 签订了UIApplicationDelegate协议
    其中的所有协议方法都是可选的) AppDelegate就和一个普通的类
    因为签订了协议 所以得到很多方法

  3. ViewController(主要负责视图管理)

  4. Main.storyboard (主要负责视图管理) LaunchScreen.storyboard
    (可视化管理 主要负责启动页)

  5. Assets.xcassets (主要用来管理图片素材) 原来叫 image.xcassets(x-code
    7 之前)

  6. LaunchScreen.storyboard

  7. info.plist (工程配置文件)
    模拟器 command + 1 ~ 5 (改变模拟器大小)
    command + ← / → 横屏 / 竖屏
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen
    mainScreen].bounds];
    // 给Window 添加颜色
    self.window.backgroundColor = [UIColor whiteColor];
    // 让Window 显示并成为主窗口
    [_window makeKeyAndVisible];
    // 从x-code7以后 必须设置 rootViewController
    // 设置Windows主窗口
    _window.rootViewController = [[ViewController alloc] init];

       // 设置坐标
       UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 270, 270)];
       view.backgroundColor = [UIColor cyanColor];
       // 将view添加到window
       [self.window addSubview:view];
    

iOS坐标系 与 数学上的坐标系不同 y轴正方向是想下的 原点是屏幕的左上角
frame bounds center 都是UIView的属性
frame (x, y, width, height) 指的是在他父视图上的位置
bounds (x, y, width, height) 指的是视图本身的坐标系 bounds x y
修改了本身的坐标 影响他的子视图 bounds (x, y) 修改的是本身的大小
根据其中心点进行收缩或扩张 bounds的改变 不会影响其中心点

  1. 使用父类初始化方法(用来显示文本)
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50,
    200, 270, 120)];
    label.backgroundColor = [UIColor blackColor];
    [_window addSubview:label];
  2. UILabel
    text
    label.text = @”美梦是个气球 牵在手上 向往蓝天 不管高低 不曾远离
    我视线 梦想是个诺言 写在心上 明天你是否会想起 昨天你写的日记
    明天你是否还惦记曾经最爱哭的你 老师们都已想不起”;
    // textColor
    label.textColor = [UIColor whiteColor];
    // font
    label.font = [UIFont systemFontOfSize:17]; // 默认17
    // label.font = [UIFont boldSystemFontOfSize:10]; 加粗
    // textAlignment 对齐方式 0 1 2 枚举
    label.textAlignment = 0;
    // numberOfLines 不确定行数时 赋值 0
    label.numberOfLines = 0;
  3. UIButton
    UIButton *button = [UIButton
    buttonWithType:UIButtonTypeSystem];
    button.frame = CGRectMake(100, 100, 60, 30);
    button.backgroundColor = [UIColor redColor];
    [_window addSubview:button];
    // 给button添加事件
    [button addTarget:self action:@selector(click:)
    forControlEvents:UIControlEventTouchUpInside];
    // 添加文字
    [button setTitle:@”确认” forState:UIControlStateNormal];
    [button setTitleColor:[UIColor whiteColor]
    forState:UIControlStateNormal];
  4. UITextField
    UITextField *textField = [[UITextField alloc]
    initWithFrame:CGRectMake(50, 370, 270, 30)];
    textField.backgroundColor = [UIColor redColor];
    [_window addSubview:textField];
    // 给输入框赋初值
    // textField.text = @”文字”;
    // 文字颜色
    textField.textColor = [UIColor blackColor];
    // borderStyle 边缘
    textField.placeholder = @”请输入密码”;
    textField.clearsOnBeginEditing = YES; // command + k

7.2 使用button 设计一个播放和暂停的功能
#import “AppDelegate.h”
#import “ViewController.h”

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.rootViewController = [[ViewController alloc] init];
UIButton *playButton = [UIButton buttonWithType:UIButtonTypeSystem];
playButton.frame = CGRectMake(50, 100, 150, 30);
playButton.backgroundColor = [UIColor redColor];
[playButton setTitle:@"播放" forState:UIControlStateNormal];
[playButton addTarget:self action:@selector(playSong:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:playButton];

// 暂停
- (void)pasueSong:(UIButton *)pasueSong {
NSLog(@"暂停");
[pasueSong removeTarget:self action:@selector(pasueSong:) forControlEvents:UIControlEventTouchUpInside];
[pasueSong addTarget:self action:@selector(playSong:) forControlEvents:UIControlEventTouchUpInside];
[pasueSong setTitle:@"播放" forState:UIControlStateNormal];
}

- (void)playSong:(UIButton *)playButton {
NSLog(@"播放");
// 移除点击事件
[playButton removeTarget:self action:@selector(playSong:) forControlEvents:UIControlEventTouchUpInside];
[playButton addTarget:self action:@selector(pasueSong:) forControlEvents:UIControlEventTouchUpInside];
[playButton setTitle:@"暂停" forState:UIControlStateNormal];
}

7.3 利用imageView设计简单动画
#import “AppDelegate.h”
#import “ViewController.h”

@interface AppDelegate ()

@end

@implementation AppDelegate

// 已经完成加载时 会走这个方法
- (BOOL)application:(UIApplication *)application     didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [[ViewController alloc] init];

UIImageView *imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIImage *image = [UIImage imageNamed:@"BackGround.png"];
[imageView setImage:image];
[self.window addSubview:imageView];

UIImageView *flowerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(55, 100, 100, 100)];
NSMutableArray *flowerArray = [NSMutableArray array];
for (int i = 1; i < 19; i++) {
    NSString *flowerName = [NSString stringWithFormat:@"flower%d.tiff", i];
    UIImage *flowerImage = [UIImage imageNamed:flowerName];
    [flowerArray addObject:flowerImage];
}
flowerImageView.animationImages = flowerArray;

flowerImageView.animationDuration = 2;
flowerImageView.animationRepeatCount = 0;
[flowerImageView startAnimating];
[self.window addSubview:flowerImageView];

UIImageView *guaImageView = [[UIImageView alloc] initWithFrame:CGRectMake(55, 200, 100, 100)];
NSMutableArray *guaArray = [NSMutableArray array];
for (int i = 1; i < 17; i++) {
    NSString *guaName = [NSString stringWithFormat:@"gua%d.tiff", i];
    UIImage *guaImage = [UIImage imageNamed:guaName];
    [guaArray addObject:guaImage];
}
guaImageView.animationImages = guaArray;

guaImageView.animationDuration = 2;
guaImageView.animationRepeatCount = 0;
[guaImageView startAnimating];
[self.window addSubview:guaImageView];

UIImageView *plantsImageView = [[UIImageView alloc] initWithFrame:CGRectMake(55, 300, 100, 100)];
NSMutableArray *plantsArray = [NSMutableArray array];
for (int i = 1; i < 10; i++) {
    NSString *plantsName = [NSString stringWithFormat:@"plants%d.tiff", i];
    UIImage *plantsImage = [UIImage imageNamed:plantsName];
    [plantsArray addObject:plantsImage];
}
plantsImageView.animationImages = plantsArray;

plantsImageView.animationDuration = 2;
plantsImageView.animationRepeatCount = 0;
[plantsImageView startAnimating];
[self.window addSubview:plantsImageView];

return YES;
}

7.4 UIViewController

  1. 在UIViewController中程序执行的顺序
    // 初始化方法

    • (instancetype)initWithNibName:(NSString *)nibNameOrNil
      bundle:(NSBundle *)nibBundleOrNil {
      self = [super initWithNibName:nibNameOrNil
      bundle:nibBundleOrNil];
      if (self) {
      // 不要再这个方法中加载视图
      // 在这个方法中去初始化一些数据相关的内容
      }
      return self;
      }

      // 加载ViewController中的view
      // UINavagationController UITableViewController在 loadView中给赋值的

      • (void)loadView {
        [super loadView];
        NSLog(@”loadView”);
        }

        // view已经加载
        // 自定义视图创建

      • (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.

        }
        // 下列方法 会执行多次+

      • (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        }

      • (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        }

      • (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        }

      • (void)viewDidDisappear:(BOOL)animated {
        [super viewDidDisappear:animated];
        }

7.5 模态跳转页面

  • (void)touchesBegan:(NSSet<UITouch *> *)touches
    withEvent:(UIEvent *)event {
    PresentViewController *present = [[PresentViewController alloc]
    init];
    // 模态出一个视图控制器
    present.modalTransitionStyle = 1; // 翻页的效果
    [self presentViewController:present animated:YES completion:nil];
    }

    • (void)touchesBegan:(NSSet> )touches withEvent:(UIEvent *)event {
      // 返回上一页 (让模态出来的页面消失)
      [self dismissViewControllerAnimated:YES completion:nil];
      }

一、新建Objective-C category文件,我这Category填MutableDeepCopy,Category
on填NSDictionary,所以生成的文件是NSDictionary+MutableDeepCopy.h和NSDictionary+MutableDeepCopy.m,生成的文件名很容易理解。 

二、两文件源代码: 

NSDictionary+MutableDeepCopy.h 

C++代码 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图