【问题标题】:NSSet of nested subproperty from set集合中嵌套子属性的 NSSet
【发布时间】:2021-08-15 17:38:04
【问题描述】:

我有一组 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"];

但如果属性发生变化,我更喜欢会引发编译器错误的东西......

【问题讨论】:

标签: ios objective-c nsset


【解决方案1】:

在 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);

【讨论】:

    【解决方案2】:

    在某处定义以下内容:

    @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 发生更改,这将给您一个编译错误。

    附言

    id 是一个错误的属性名称,因为它也是一个内置类型名称。考虑改用identifier 属性名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-11
      • 2020-11-23
      • 1970-01-01
      相关资源
      最近更新 更多