I have a set of someProtocol objects, I'd like to make a set from a NSString nested property on this object:
// Protocol SomeProtocol
@protocol SomeProtocol<NSObject>
@property(nonatomic, readonly) id<SomeSubProtocol> someSubProtocolObject;
@end
// Protocol SomeSubProtocol
@protocol SomeSubProtocol<NSObject>
@property(nonatomic, readonly) NSString *Id;
@end
I have a set of SomeProtocols:
NSSet<id<SomeProtocol>> *setOfSomeSubProtocols;
I'd like to get a NSSet of the Id properties:
NSSet<NSString *> *idSet = ?; // Calculate from arrayOfSomethings.
I've tried:
idSet = [setOfSomeSubProtocols valueForKeyPath @"someSubProtrocolObject.id"];
But I'd prefer something that throws a compiler error if the properties change...
In Swift, I would have suggested to use map()
, but it doesn't exists in Objective-C. You can search or implement yourself a version of map
in Objective-C.
But, what you can do, is a manual loop, since it's a normal approach of the issue.
__block NSMutableSet *ids = [[NSMutableSet alloc] init];
[setOfSomeSubProtocols enumerateObjectsUsingBlock:^(id<SomeProtocol> _Nonnull obj, BOOL * _Nonnull stop) {
[ids addObject:[[obj someSubProtocolObject] identifier]];
}];
It's quite simple and does the job.
You could as said before, implement a map
on NSSet
, something like this:
@implementation NSSet(Map)
-(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;
}
With call:
NSSet *ids = [setOfSomeSubProtocols mapWithBlock:^id (id<SomeProtocol> object) {
return [[object someSubProtocolObject] identifier];
}];
NSLog(@"ids: %@", ids);