Objective-C实训(六)

2017-08-21  本文已影响0人  无厘小阿先_

练习与示例:

1.代理

@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
-(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(@"带孩子去上班");
    }
}
#import "Boss.h"
@interface Worker : NSObject<NannyDelegate>
- (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.类的扩展

- (void)sayHi;

- (void)getCharacterOfPre;
// 为NSString类扩展一个新的方法,要求获取字符串的首字母并且将该首字母大写。
- (NSString *)firstCharacter;
- (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;
}
@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系统管理内存,不需要开发人员手动管理。
上一篇下一篇

猜你喜欢

热点阅读