来自集合的嵌套子属性的 NSSet
NSSet of nested subproperty from set
我有一组 someProtocol 对象,我想从这个对象上嵌套 属性 的 NSString 创建一组:
// Protocol SomeProtocol
@protocol SomeProtocol<NSObject>
@property(nonatomic, readonly) id<SomeSubProtocol> someSubProtocolObject;
@end
// Protocol SomeSubProtocol
@protocol SomeSubProtocol<NSObject>
@property(nonatomic, readonly) NSString *Id;
@end
我有一组 SomeProtocols:
NSSet<id<SomeProtocol>> *setOfSomeSubProtocols;
我想要获取 Id 属性的 NSSet:
NSSet<NSString *> *idSet = ?; // Calculate from arrayOfSomethings.
我试过:
idSet = [setOfSomeSubProtocols valueForKeyPath @"someSubProtrocolObject.id"];
但我更喜欢在属性更改时抛出编译器错误的东西...
在某处定义以下内容:
@protocol KeyPath <NSObject> @end
typedef NSString<KeyPath> KeyPath;
NS_INLINE KeyPath *GetKeyPath(__unused unsigned long val, NSString *str) { return (KeyPath *)str; }
#define PRIVATE_KEYPATH(obj, key) GetKeyPath(sizeof(obj.key), @#key)
#define PROTOCOL_KEYPATH(proto, key) PRIVATE_KEYPATH(((id<proto>)nil), key)
然后像这样使用它:
[setOfSomeSubProtocols valueForKeyPath:PROTOCOL_KEYPATH(SomeSubProtocol, Id)];
如果 SomeSubProtocol
的类型名称或 属性 名称 Id
更改,这将给您一个编译错误。
P.S.
id
是一个糟糕的 属性 名称,因为它也是一个内置类型名称。考虑改用 identifier
属性 名称。
在 Swift 中,我建议使用 map()
,但在 Objective-C 中不存在。您可以在 Objective-C.
中搜索或实现自己的 map
版本
但是,您可以做的是手动循环,因为这是解决问题的正常方法。
__block NSMutableSet *ids = [[NSMutableSet alloc] init];
[setOfSomeSubProtocols enumerateObjectsUsingBlock:^(id<SomeProtocol> _Nonnull obj, BOOL * _Nonnull stop) {
[ids addObject:[[obj someSubProtocolObject] identifier]];
}];
它非常简单并且可以完成工作。
您可以如前所述,在 NSSet
上实施 map
,如下所示:
@implementation NSSet(地图)
-(NSSet *)mapWithBlock:(id (^)(id))block {
__block NSMutableSet *set = [[NSMutableSet alloc] init];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
id mappedObject = block(obj);
[set addObject:mappedObject];
}];
return set;
}
通话中:
NSSet *ids = [setOfSomeSubProtocols mapWithBlock:^id (id<SomeProtocol> object) {
return [[object someSubProtocolObject] identifier];
}];
NSLog(@"ids: %@", ids);
我有一组 someProtocol 对象,我想从这个对象上嵌套 属性 的 NSString 创建一组:
// Protocol SomeProtocol
@protocol SomeProtocol<NSObject>
@property(nonatomic, readonly) id<SomeSubProtocol> someSubProtocolObject;
@end
// Protocol SomeSubProtocol
@protocol SomeSubProtocol<NSObject>
@property(nonatomic, readonly) NSString *Id;
@end
我有一组 SomeProtocols:
NSSet<id<SomeProtocol>> *setOfSomeSubProtocols;
我想要获取 Id 属性的 NSSet:
NSSet<NSString *> *idSet = ?; // Calculate from arrayOfSomethings.
我试过:
idSet = [setOfSomeSubProtocols valueForKeyPath @"someSubProtrocolObject.id"];
但我更喜欢在属性更改时抛出编译器错误的东西...
在某处定义以下内容:
@protocol KeyPath <NSObject> @end
typedef NSString<KeyPath> KeyPath;
NS_INLINE KeyPath *GetKeyPath(__unused unsigned long val, NSString *str) { return (KeyPath *)str; }
#define PRIVATE_KEYPATH(obj, key) GetKeyPath(sizeof(obj.key), @#key)
#define PROTOCOL_KEYPATH(proto, key) PRIVATE_KEYPATH(((id<proto>)nil), key)
然后像这样使用它:
[setOfSomeSubProtocols valueForKeyPath:PROTOCOL_KEYPATH(SomeSubProtocol, Id)];
如果 SomeSubProtocol
的类型名称或 属性 名称 Id
更改,这将给您一个编译错误。
P.S.
id
是一个糟糕的 属性 名称,因为它也是一个内置类型名称。考虑改用 identifier
属性 名称。
在 Swift 中,我建议使用 map()
,但在 Objective-C 中不存在。您可以在 Objective-C.
map
版本
但是,您可以做的是手动循环,因为这是解决问题的正常方法。
__block NSMutableSet *ids = [[NSMutableSet alloc] init];
[setOfSomeSubProtocols enumerateObjectsUsingBlock:^(id<SomeProtocol> _Nonnull obj, BOOL * _Nonnull stop) {
[ids addObject:[[obj someSubProtocolObject] identifier]];
}];
它非常简单并且可以完成工作。
您可以如前所述,在 NSSet
上实施 map
,如下所示:
@implementation NSSet(地图)
-(NSSet *)mapWithBlock:(id (^)(id))block {
__block NSMutableSet *set = [[NSMutableSet alloc] init];
[self enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) {
id mappedObject = block(obj);
[set addObject:mappedObject];
}];
return set;
}
通话中:
NSSet *ids = [setOfSomeSubProtocols mapWithBlock:^id (id<SomeProtocol> object) {
return [[object someSubProtocolObject] identifier];
}];
NSLog(@"ids: %@", ids);