美文网首页
Objective-C实训(六)

Objective-C实训(六)

作者: 无厘小阿先_ | 来源:发表于2017-08-21 20:03 被阅读0次

    练习与示例:

    1.代理

    • 新建Boss类,在.h中声明其方法和代理属性:
    @protocol NannyDelegate <NSObject>
    - (void)washClothes;
    - (void)cook;
    
    @optional
    - (void)takeCareBaby;
    @end
    
    @interface Boss : NSObject
    //实现了这个协议的任意类型的对象
    // 代理属性要用assign和weak去修饰,不需要使用oc中的内存管理
    @property (nonatomic, assign)id<NannyDelegate>delegate;
    -(void)clothesDirty;
    -(void)hungry;
    -(void)working;
    @end
    
    • 在.m中实现方法:
    -(void)clothesDirty {
        NSLog(@"衣服脏了");
        [self.delegate washClothes];
    }
    
    -(void)hungry {
        NSLog(@"饿了");
        [self.delegate cook];
    }
    
    -(void)working {
        NSLog(@"去上班");
        // 判断我的代理人能否响应(是否实现)某方法
        if ([self.delegate respondsToSelector:@selector(takeCareBaby)]) {
            [self.delegate takeCareBaby];
        } else {
            NSLog(@"带孩子去上班");
        }
    }
    
    • 新建一个Worker类,导入头文件并继承Boss类的代理:
    #import "Boss.h"
    @interface Worker : NSObject<NannyDelegate>
    
    • 在.h中实现:
    - (void)washClothes {
        NSLog(@"洗衣服");
    }
    
    //- (void)cook {
    //    NSLog(@"做饭");
    //}
    - (void)cook {
        NSLog(@"zuofan");
    }
    
    - (void)takeCareBaby {
        NSLog(@"保姆照顾孩子");
    }
    
    • 在主函数中导入头文件:
    #import "Boss.h"
    #import "Worker.h"
    
    • 在主函数中实现:
        Boss *boss = [[Boss alloc]init];
        Worker *worker = [[Worker alloc]init];
        boss.delegate = worker;
        [boss hungry];
        [boss clothesDirty];
        [boss working];
    

    2.类的扩展

    • 新建OC文件SayHi为NSString类,在.h中进行方法的声明:
    - (void)sayHi;
    
    - (void)getCharacterOfPre;
    // 为NSString类扩展一个新的方法,要求获取字符串的首字母并且将该首字母大写。
    - (NSString *)firstCharacter;
    
    • 在.m中进行实现:
    - (void)sayHi {
        NSLog(@"我是%@,我是一个牛逼的字符串", self);//self指的是当前调用这个方法的字符串对象
    }
    
    - (void)getCharacterOfPre {
        NSString *s = [[self substringToIndex:1] capitalizedString];
        NSLog(@"%@", s);
    }
    
    - (NSString *)firstCharacter {
        if (self.length > 0) {
            return [[self substringToIndex:1] uppercaseString];
        }
        NSLog(@"空字符串别凑热闹");
        return @"";//或者写nil或self 
    }
    
    • 在主函数中进行头文件导入:
    #import "NSString+SayHi.h"
    
    • 在主函数中进行调用:
    int main(int argc, const char * argv[]) {
        
        [@"徐博杰" sayHi];
        [@"dfdf" getCharacterOfPre];
        NSLog(@"%@", [@"abc" firstCharacter]);
        return 0;
    }
    
    • 新建一个Person类,在.m中自定义初始化方法:
    @interface Person ()
    
    @property(nonatomic, retain) NSString *age;
    
    @end
    
    @implementation Person
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            //私有方法通常是通过其它方法间接调用,目的是将某一部分的代码分装起来,多次使用
            [self sayHi];
        }
        return self;
    }
    
    // 没在.h中声明的都是私有方法
    - (void)sayHi {
        NSLog(@"hahahaha");
    }
    
    @end
    

    3.省市区

         NSMutableArray *provinceArray = [NSMutableArray array];
            
         // 加载文件得到字符串
         // 参数一:文件路径
         // 参数二:编码格式
         // 参数三:错误信息
         NSString *contentString = [NSString stringWithContentsOfFile:@"area.txt" encoding:NSUTF8StringEncoding error:nil];
         // NSLog(@"%@", contentString);
         // 以换行符分割字符串,得到每一行的字符串内容
         NSArray *lineArray = [contentString componentsSeparatedByString:@"\n"];
         for (NSString *lineString in lineArray) {
    //          NSLog(@"line:%@", lineString);
                if (![lineString hasPrefix:@" "]) {
                    // 前缀不是空格是省名
                    
                    // 创建一个省份字典
                    NSMutableDictionary *provinceDic = [NSMutableDictionary dictionary];
                    // 省份字典添加键值对(provinceName:省份名)
                    [provinceDic setObject:lineString forKey:@"provinceName"];
                    // 创建一个城市数组(用于后面存放城市字典)
                    NSMutableArray *cityArray = [NSMutableArray array];
                    // 添加键值对(cityName:城市名)
                    [provinceDic setObject:cityArray forKey:@"cityArray"];
                    [provinceArray addObject:provinceDic];
                    
                } else if (![lineString hasPrefix:@"    "]) {
                    // 前缀有空格且不是四个空格为城市名
                    
                    // 读取到城市名的时候需要找到该城市所属省份(当前省份数组中最后一个元素就是当前城市所属省份)
                    NSMutableDictionary *provinceDic = [provinceArray lastObject];
                    NSMutableArray *cityArray = [provinceDic objectForKey:@"cityArray"];
                    
                    // 创建城市字典
                    NSMutableDictionary *cityDic = [NSMutableDictionary dictionary];
                    // 添加键值对(cityName:城市名)
                    [cityDic setObject:lineString forKey:@"cityName"];
                    
                    //创建地区数组(后面用于存放地区名称)
                    NSMutableArray *areaArray = [NSMutableArray array];
                    // 添加键值对(areaArray:地区数组)
                    [cityDic setObject:areaArray forKey:@"areaArray"];
                    //将城市的字典存到对应的城市数组中
                    [cityArray addObject:cityDic];
                        
                } else {
                    // 前缀有空格且有四个空格的为地区名
                    
                    // 获取当前地区所在省份
                    NSMutableDictionary *provinceDic = [provinceArray lastObject];
                    // 获取该省份的城市数组
                    NSMutableArray *cityArray = [provinceDic objectForKey:@"cityArray"];
                    // 从城市数组中获取当前城市所属城市
                    NSMutableDictionary *cityDic = [cityArray lastObject];
                    // 获取该城市的地区数组
                    NSMutableArray *areaArray = [cityDic objectForKey:@"areaArray"];
                    // 将地区名存到该地区数组
                    [areaArray addObject:lineString];
                    
                }
            }
            
        for (NSMutableDictionary *provinceDic in provinceArray) {
            NSLog(@"省份:%@", [provinceDic objectForKey:@"provinceName"]);
            for (NSMutableDictionary *cityDic in [provinceDic objectForKey:@"cityArray"]) {
                NSLog(@"城市:%@", [cityDic objectForKey:@"cityName"]);
                for (NSString *areaName in [cityDic objectForKey:@"areaArray"]) {
                    NSLog(@"地区:%@", areaName);
                }
            }
        }
    

    知识点:

    1.属性的内存管理

    语义特性              使用范围
    assign              基本数据类(char, short, int, float, double)
    retain              对象类型
     copy               对象类型,且遵守了<NSCopying>协议 
    

    2.集合的内存管理

    1️⃣常见的集合类有:NSArray,NSDictionary,NSSet。
    2️⃣集合会自主管理集合内部元素。
    3️⃣集合内存管理的方式:
      加入集合的元素会被retain;
      移除出集合的元素会被release;
      集合被释放时,会对集合中所有元素release;
    

    3.KVC

    1️⃣KVC:Key Value Coding,键值编码,是一种间接访问实例变量的方法。
    2️⃣KVC提供了一种使用字符串(key)而不是访问器方法,去访问一个对象实例变量的机制。
    3️⃣KVC中常用的方法:
    - (id)valueForKey:(NSString *)key;
    - (void)setValue:(id)value forKey:(NSString *)key;
    - (id)valueForKeyPath:(NSString *)keyPath;
    - (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
    - (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
    4️⃣KVC按顺序使用如下技术:
      1)、检查是否存在getter方法-<key>或者setter方法-set<key>:的方法;
      2)、如果没有上述方法,则检查是否存在名字为-_<key>、<key>的实例变量;
      3)、如果仍未找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
    

    4.ARC

    ARC:Automatic Reference Counting,自动引用计数,由开发人员开辟内存空间,但是不需要释放该内存空间,由系统自动释放该空间。
    ARC本质上还是基于MRC的,只不过是系统自动添加了释放内存的方法。
    ARC是编译器特性,而不是运行时特性,更不是垃圾回收器(GC)。
    从Xcode5.0后,创建的工程默认是开启ARC的。
    当工程开启ARC后,由于编译器会自动帮你释放内存,所有和内存相关操作retain、release、autorelease,都不能写。
    当重写dealloc方法时, 也不能写[super dealloc],否则会报错。
    
    ARC中的属性语义特性:
    语义特性             使用范围
    assign             基本数据类(char, short, int, float, double)
    strong             对象类型,相当于MRC中的retain
     copy              对象类型,且遵守了<NSCopying>协议
     weak              对象类型,但是内部不会对对象做retain的操作
    
    ARC与MRC的混编:
    如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Sources,在里面找到对应文件,添加flag:
    打开ARC:-fobjc-arc
    关闭ARC:-fno-objc-arc
    

    5.总结

    1️⃣assign、retain、copy对应不同的setter实现。为实例变量赋值时,尽量使用setter方法,再次赋值时,会把之前值release。
    2️⃣dealloc在对象引用计数为0时自动调用,不要显示调用。dealloc实现内部,先要释放实例变量,然后执行[super dealloc]。
    3️⃣便利构造器的内存管理是借助autorelease实现的。
    4️⃣集合会管理自己的元素。
    5️⃣KVC是一种间接访问实例变量的方法。
    6️⃣ARC系统管理内存,不需要开发人员手动管理。
    

    相关文章

      网友评论

          本文标题:Objective-C实训(六)

          本文链接:https://www.haomeiwen.com/subject/ethhdxtx.html