iOS开发经验(2)

目录

  1. KVC
  2. 观察者模式:KVO与通知
  3. 精度问题
  4. 三目运算符
  5. 点语法
1. KVC(Key-value coding)键值编码。用字符串动态去操作对象

其实现方法是使用字符串描述要更改的对象状态部分。通过Key名直接访问对象的属性,或者给对象的属性赋值。这样就可以在运行时动态在访问和修改对象的属性。而不是在编译时确定。

所有的对象都可以使用KVC
键统一是字符串,而值是不支持基本数据类型的,必须将值转换为NSNumber或者NSValue类型

操作对象的属性和对象属性的属性,访问变量的属性,即使该属性没有get,set方法也可以调用

Human *human = [[Human alloc]init];       
//将name属性设置为"holydancer"       
[human setValue:@"holydancer" forKey:@"name"];
//将human中的name属性取出  
NSString *nameOfHuman=[human valueForKey:@"name"];

KVC集合运算符

    ProductModel *model = [[ProductModel alloc]init];
    model.name = @"iMac";
    model.price = @18888;
    ProductModel *model1 = [[ProductModel alloc]init];
    model1.name = @"iphone";
    model1.price = @6999;
    NSArray *array = @[model,model1];

简单类型的集合操作符:返回 strings, numbers, dates,简单集合操作符作用于 array 或者 set 中相对于集合操作符右侧的属性。包括 @avg, @count, @max, @min, @sum.

NSString *name = [array valueForKeyPath:@"@count"];//返回集合中对象总数的 NSNumber 对象。操作符右边没有键路径。
NSNumber  *price_max = [array valueForKeyPath:@"@max.price"];//比较由操作符右边的键路径指定的属性值,并返回比较结果的最大值。最大值由指定的键路径所指对象的 compare: 方法决定
NSString *price_min = [array valueForKeyPath:@"@min.price"];//返回的是集合中的最小值
NSNumber  *price_sum = [array valueForKeyPath:@"@sum.price"];//属性值的总和
NSNumber  *price_avg = [array valueForKeyPath:@"@avg.price"];//转换为 double, 计算其平均值,返回该平均值的 NSNumber 对象。当均值为 nil 的时候,返回 0.

提示:你可以简单的通过把 self 作为操作符后面的 key path 来获取一个由 NSNumber 组成的数组或者集合的总值,例如对于数组 @[@(1), @(2), @(3)] 可使用 valueForKeyPath:@"@max.self" 来获取最大值。

NSLog(@"%@,%@,%@,%@,%@",name,price_max,price_min,price_sum,price_avg);

对象操作符,返回 NSArray 对象实例:对象操作符包括 @distinctUnionOfObjects 和 @unionOfObjects, 返回一个由操作符右边的 key path 所指定的对象属性组成的数组。其中 @distinctUnionOfObjects 会对数组去重,而 @unionOfObjects 不会。

    NSArray *unionOfObjects = [array valueForKeyPath:@"@unionOfObjects.name"]; // 1.
    NSArray *distinctUnionObjects = [array valueForKeyPath:@"@distinctUnionOfObjects.name"];  //2.
    NSLog(@"%@,%@",unionOfObjects,distinctUnionObjects);

数组和集合操作符,返回的是一个 array 或者 set 对象
数组和集合操作符作用对象是嵌套的集合,也就是说,是一个集合且其内部每个元素是一个集合。数组和集合操作符包括 @distinctUnionOfArrays,@unionOfArrays,@distinctUnionOfSets:
@distinctUnionOfArrays / @unionOfArrays 返回一个数组,其中包含这个集合中每个数组对于这个操作符右面指定的 key path 进行操作之后的值。 distinct 版本会移除重复的值。
@distinctUnionOfSets 和 @distinctUnionOfArrays 差不多, 但是它期望的是一个包含着 NSSet 对象的 NSSet ,并且会返回一个 NSSet 对象。因为集合不能包含重复的值,所以它只有 distinct 操作。

NSArray *array1 = @[model,model1];
NSArray *totalArray = @[array,array1];
NSArray *distinctUnionOfArrays = [totalArray valueForKeyPath:@"@distinctUnionOfArrays.name"];
NSArray *unionOfArrays = [totalArray valueForKeyPath:@"@unionOfArrays.name"];
NSLog(@"%@,%@",distinctUnionOfArrays,unionOfArrays);

注意: 如果操作符右侧 key path 指定的对象为 nil,那么返回的数组中会包含 NSNull 对象.

  • 四个主要方法
    必须手动将值类型转换成NSNumber或者NSValue类型,才能设置为value
- (void)setValue:(nullable id)value forKey:(NSString *)key; 
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

valueForKey:总是返回一个id对象,如果原本的变量类型是值类型或者结构体,返回值会封装成NSNumber或者NSValue对象。

- (nullable id)valueForKey:(NSString *)key; 
- (nullable id)valueForKeyPath:(NSString *)keyPath; 
  • 嵌套数据,KEY为数组或者字典

    • 对于有序的容器,可以用下面的方法:
       - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    
    • 对于无序的容器,可以用下面的方法:
      - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;
      
  • 键路径:嵌套数据中,使用KeyPath

  • KVC中处理异常情况

    • 如果某对象有一个常用数据类型,比如bool,在用setvalue:设置value的时候,需要实现 setNilValueForKey:(NSString *)key
  • 在用set value: 设置value的时候,如果该对象不存在该属性,比如bool,需要实现 - (void)setValue:(id)value forUndefinedKey:(NSString *)key

  • KVC使用场景

    • 动态地取值和设值:利用KVC动态的取值和设值是最基本的用途了。
  • 用KVC来访问和修改私有变量:利用KVC可以随意修改一个对象的属性和变量(即使是私有变量)
    对于类里的私有属性,Objective-C是无法直接访问的,但是KVC是可以的。

  • Model和字典转换

  • 利用KVC集合运算符,KVC可以通过运算符层次查找对象的属性;KVC获取值不仅可以返回一个数据,还可以将某一个属性的所有值,数据归类出来(B不一定是类,也可以是数组)

  • 利用KVC可以修改系统的只读变量,修改一些控件的内部属性
    这也是iOS开发中必不可少的小技巧。众所周知很多UI控件都由很多内部UI控件组合而成的,但是Apple度没有提供这访问这些空间的API,这样我们就无法正常地访问和修改这些控件的样式。而KVC在大多数情况可下可以解决这个问题。最常用的就是个性化UITextField中的placeHolderText了。

因为数据造成crash的原因大概几点:

  1. 使用字面量创建数组、字典,valuenil
  2. 使用KVC方法给数组字典赋值为nil
  3. null发送方法。其他的诸如null的判断方法及给控件赋值都不会引起crash。
2. 观察者模式:KVO与通知

iOS的一种设计模式, 观察者设计模式,依赖于 Objective-C 强大的 Runtime。观察者模式包含:

1.通知机制(notification)
2.KVO机制【可参考iOS--KVO的实现原理与具体应用】

  • 通知机制:
    委托机制是代理“一对一”的对象之间的通信,而通知机制是广播“一对多”的对象之间的通信。
//A类获取通知中心,并发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"statusBarHidden" object:nil userInfo:dic];
//B类注册通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarHidden:) name:@"statusBarHidden" object:nil];
//释放所有通知
- (void)removeObserver:(id)observer;
//释放名称为aName的通知
- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;
  • KVO
    KVO提供一种机制,指定一个被观察对象,当对象某个属性发生更改时,对象会获得通知,并作出相应处理。KVO这种编码方式使用起来很简单,很适用与model修改后,引发的UIVIew的变化这种情况,当更改属性的值后,监听对象会立即得到通知;当指定的对象的属性被修改后,对象就会接受到通知,****前提是执行了setter方法、或者使用了KVC赋值****。
    当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。

原理:

  • 当一个object有观察者时,动态创建这个object的类的子类
  • 对于每个被观察的property,重写其set方法
  • 在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
  • 当一个property没有观察者时,删除重写的方法
  • 当没有observer观察任何一个property时,删除动态创建的子类
    • 注册,指定被观察者的属性
[objc addObserver:self forKeyPath:@"title" options:
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
  • 实现回调方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{}
  • 移除观察
[self removeObserver:self forKeyPath:@"title" context:nil];
  • 两者区别:
    notification比KVO多了发送通知的一步。两者都是一对多,但是对象之间直接的交互,notification明显多,需要notificationCenter来做为中间交互。
    notification的优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,例如键盘、前后台等系统通知的使用也更显灵活方便.
3. 精度问题
  • 原因:
    NSNumberdescription方法不够严谨,在调用NSNumber的description方法打印数值时,会发生精度损失。
  • 建议 :
    • 如果是double类型,处理精度有关的数据用double。建议把NSNumber转换成double再进行输出(NSString)或计算(CGFloat);
    • 有关浮点型数据,后台传字符串的格式,防止丢失精度.
 NSNumber *value=dic[@"number"];
 NSLog(@"value:%@", value);

输出:value:81.59999999999999
如果是double类型,建议把NSNumber转换成double再进行输出或计算 。

CGFloat numberValue = [self doubleValue];
NSString *value=[NSString stringWithFormat:@"%g",[dic[@"number"] doubleValue]];
4. 三目运算符
  • 基本格式 : (关系表达式) ? 表达式1 : 表达式2;
  • 执行流程 : 关系表达式为 真 返回表达式1 关系表达式为假 返回表达式2
    int num1=8,num2=3,result=0;
    result= num1>num2?num1:num2;
    //因为num1>num2 成立  所以最后结果为num1的值
5. 点语法
  • 点语法的本质还是方法调用,当使用点语法时,编译器会自动展开成相应的方法,而不是访问成员变量.
  • 切记点语法的本质是转换成相应的对settergetter方法调用,如果没有setget方法,则不能使用点语法。
  • 不要在gettersetter方法中使用本属性的点语法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容

  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    黑暗中的孤影阅读 49,682评论 74 441
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    朽木自雕也阅读 1,552评论 6 1
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    Fendouzhe阅读 670评论 0 6
  • KVC简单介绍 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过Key...
    公子无礼阅读 1,383评论 0 6
  • 坐在公交车上,拿着手机读着白夜行,心里却在想,十年前的今天我一定不会想到,以后会做着一份平凡的工作,拿着平凡的收入...
    瓶瓶瓶子_阅读 180评论 0 1