KeyPathExtension
-
Objective C运行时中KVC的KeyPath扩展。
-
用更少的代码描述复杂的逻辑,减少程序员的工作量。
- 在KeyPath中直接访问结构体值。
- 在KeyPath中使用谓词。
- 实现自定义函数或@NSKeyValueOperator(@avg, @count, ...)。
- 在KeyPath中直接执行类型安全检查。
- 小步快跑。
-
用较少的代码描述复杂的逻辑,减少工作量。
- 在KVC中直接访问结构体成员。
- 在KVC中使用谓词。
- 实现自定义函数或@NSKeyValueOperator(@avg, @count, ...)
- 在KVC中直接进行类型安全检查。
- 随手点赞,好运连连。
-
关键词:
KeyPath Extension
KVC Extension
按Path排序
导入
- 将
KeyPathExtension
目录下的所有源文件拖到您的项目中。
#import "KeyPathExtension.h"
- 或者使用
CocoaPods
。
pod 'KeyPathExtension'
iOS
&macOS
概述
示例
[... kpe_setValue:@(100) forExtensionPath:@"....frame->size->width"];
[... kpe_setValue:@(YES) forExtensionPath:@"...dogs.@:age<1!.smallDog"];
[... kpe_valueForExtensionPath:@"view.subviews.@:hidden == YES!.@removeFromSuperview"];
///myStarts is outlet collections
myStarts
.akvcSetValueForExtensionPath(@(NO), @"seleced")
.akvcSetValueForExtensionPathWithFormat(@(YES), @"@:tag <= %ld!.seleced", sender.tag);
///Get the path in a different way.
@akvcGetPath(object, a.b.c.d).akvcPathAppend(@"e.f.g.h").akvcPathAppendCode(h.i.j.k);
内容
扩展路径
全部功能
Name Representation
-------------------------------------
StructPath : NSKeyPath->StructKey
Indexer : @[...]
PathFunction : @PathFunction
Subkey : <...>
Regkey : <$...$>
SELInspector : SEL(...)?
ClassInspector : Class(...)?
KeysAccessor : {KeyPath,KeyPath, ...}
PredicateFilter : @:...!
PredicateEvaluate : @:...?
-------------------------------------
结构路径
StructPath可以访问结构。
- 使用访问器
->
访问结构中的属性。结构体访问符
@"...NSKeyPath->StructKey->StructKey";
索引器
提供了一种简单的方式来访问键路径中的数组元素。
Provides a simple way to access array elements in key path.
@[0] ; @[0,1] ;
Use the index symbol 'i' to find elements within the array range.
@[i <= 3 , i > 5];
Use the index symbol '!' You can exclude elements from an array.
@[!0,!1] ; @[i != 0 , i != 1] ; @[i<5 , 9] ; @[i<5 , !3] ;
Confirm elements and deny elements cannot exist at the same time.真假不能同时存在!
It's wrong : @[0,!1] ;
PathFunction
PathFunction 是一个自定义的 NSKeyValueOperator。自定义路径函数
[... kpe_valueForExtensionPath:@"...friendList.@sortFriends..."];
Regist PathFunction
[KeyPathExtension registFunction:@"sortFriends" withBlock:^id(id _Nullable target) {
//... ...
//return result;
}];
Default PathFunction 默认路径函数
name
--------------------
@nslog
@isNSNull
@isAllEqual
@lastObject
@firstObject
@isAllDifferent
--------------------
默认行为
- 当调用未注册的方法时,函数名称将以选择器名称的方式调用。如果有返回值,则返回;如果没有返回,则返回目标本身。
id viewThatRemoved = [... kpe_valueForExtensionPath:@"view.@removeFromSuperview"];
- 可以使用带有参数的方法,但不推荐这样做。所有参数都是默认值。
id mulArraySelf = [mulArray kpe_valueForExtensionPath:@"@removeObjectAtIndex:.@removeObjectAtIndex:"];
Equivalent ==>
[mulArray removeObjectAtIndex:0];
[mulArray removeObjectAtIndex:0];
id mulArraySelf = mulArray;
子键
属性键的子字符串。
- 表达式:
<...>
`time` can match 'createTime' and 'modifyTime'.
[... kpe_valueForExtensionPath:@"...<time>.@isAllEqual"];
注册密钥
属性键的表达式。
- 表达式:
<$...$>
`button\\d+` can match 'button0','button1', ...
[... kpe_setValue:@(YES) forExtensionPath:@"...<button\\d+>.hidden"];
SELInspector
如果 iSELInspector 是最后一个组件,则它等价于 - respondsToSelector: .
- 表达式:
SEL(...)?
NSNumber *value = [... kpe_valueForExtensionPath:@"...SEL(addObject:)?"];
如果 SELInspector 不是最后一个组件,则它是执行下一路径的条件。
[... kpe_setValue:@"Trump" forExtensionPath:@"...friend.SEL(setNickName:)?.nickName"];
类检查器
如果类检查器是最后一个组件,它等同于 isKindOfClass: .
- 表达式:
Class(...)?
[... kpe_valueForExtensionPath:@"...Class(NSArray)?"];
如果类检查器不是最后一个组件,它是在执行下一个路径的条件。
[... kpe_setValue:@"Trump" forExtensionPath:@"...friend.Class(AkvcPerson)?.nickName"];
KeysAccessor
使用Keysaccessor可以同时访问多个路径。返回结果按顺序放置在数组中。多键访问,返回按顺的数组
- 讨论:在KeysAccessor中,谓词(Predicate)、子键(Subkey)、注册键(Regkey)被禁用!另外,nil值将替换为NSNull。
- 表达式:
{...}
[... kpe_valueForExtensionPath:@"{Breakfast.name, lunch.name, dinner.name}.@isAllEqual"];
谓词过滤器
PredicateFilter 等于 - filteredArrayUsingPredicate
- 表达式:
@:PredicateString!
- 讨论:符号
!.
或?.
不应使用,但?
、!
、.
可用。
[... kpe_valueForExtensionPath:@"...users.@:age>18 && sex == 0!"];
在 ExtensionPath 中为 predicate 组件使用占位符
- 讨论:参数列表只接受装箱参数。使用
AkvcBoxValue(...)
拼接标量。
[... kpe_valueForExtensionPathWithPredicateFormat:@"...@:@K == %@!...@:SELF == %@?", object0, object1, object2];
PredicateEvaluate
PredicateEvaluate 等于 - evaluateWithObject: . 参考 PredicateFilter
- 表达式:
@:PredicateString?
...?
Component Class(...)?
(ClassInspector),SEL(...)?
(SELInspector),@:...?
(PredicateEvaluate)
这些组件都具有此特性:如果不是最后一个组件,将作为一个条件来确定是否执行下一个路径。如果为 false,则返回 nil 或不执行任何操作,否则执行下一个路径。- 在路径中这类组件表示执行条件,false 时返回 nil 或不进行任何操作,true 时继续执行。
注册自定义结构体
- 注册自定义结构体需要2个方法:
+ registStruct:getterMap:
和+ registStruct:setterMap:
- getter map 或 setter map 的键是结构体成员名称
- getter map 的值是一个类似以下块的代码:
__kindof NSValue*(^GetBlockType)(NSValue* value)
@{
@"size" : ^(NSValue* value){
return [NSValue valueWithCGSize:[value CGRectValue].size];
} ,
... ...
}
- setter map 的值是一个类似以下块的代码:
__kindof NSValue*(^SetBlockType)(NSValue* value , id newValue)
@{
@"size" : ^(NSValue* value , id newValue){
CGRect rect = [value CGRectValue];
rect.size = [newValue CGSizeValue];
return [NSValue valueWithCGRect:rect];
} ,
... ...
}
清除缓存
[KeyPathExtension cleanCache];
链式编程
NSObject+KeyPathExtensionChain.h
定义了链式编程的 API,所有 setter 的返回值都是目标本身。
_NonnullObject.akvcSetValueForExtensionPath(...)akvcSetValueForExtensionPath(...)...
需要扩展 KeyPathExtension
- 紧急情况:[email protected]