1

In KVC, I usually use setValues:forKeyPath: to set the same value for objects in a collection. E.g.:

NSMutableArray <SomeClass *> *arr = [[NSMutableArray alloc] initWithCapacity:10];
for (int i = 0; i < 10; i++) {
    SomeClass *obj = [[SomeClass alloc] init];
    obj.stringProp = @(i).stringValue;
    [arr addObject:obj];
}

NSLog(@"- %@", [arr valueForKeyPath:@"stringProp"]);
[arr setValuesForKeysWithDictionary:@{@"stringProp" : @"Same same!"}];

NSLog(@"- %@", [arr valueForKeyPath:@"stringProp"]);
[arr setValue:@"Another" forKeyPath:@"stringProp"];

NSLog(@"- %@", [arr valueForKeyPath:@"stringProp"])

But, for a dictionary, can we use that as well? Now I've gotta set values manually:

NSMutableDictionary *myDict;
//... setupValues
NSString *valueToSet = @"Hehe";
for (NSString *key in myDict) {
    [myDict setObject:valueToSet forKey:key];
}

Is there a simple solution for a dictionary, like the example above?

jscs
  • 63,694
  • 13
  • 151
  • 195
Eddie
  • 1,903
  • 2
  • 21
  • 46

2 Answers2

1

I'm not sure if there is a function for that (I guess it don't), but in case you gonna need to do that multiple times, you can add a function to NSMutableDictionary to help you with that:

@interface NSMutableDictionary (NSMutableDictionarySetAllKeysObject)
-(void)setAllKeysObject:(nonnull id)object;
@end

@implementation NSMutableDictionary (NSMutableDictionarySetAllKeysObject)
-(void)setAllKeysObject:(nonnull id)object
{
    for (NSString *key in self.allKeys) {
        [self setObject:object forKey:key];
    }
}
@end

So you would be able to do that:

NSString *valueToSet = @"Hehe";
[myDict setAllKeysObject:valueToSet];
VitorMM
  • 1,060
  • 8
  • 33
  • probably they don't have a function for that (yet?). I'll accept your answer in a few days, in case someone found a way I asked for :p – Eddie Mar 12 '17 at 10:04
1

You can use allValues method to get all values as an NSArray first. Then get a mutable copy of the array. Lastly, use any of the KVC methods you mentioned in your question on the mutable array (setValuesForKeysWithDictionary, setValue:forKeyPath:, etc...)


Based on your example

[[[myDict allValues] mutableCopy] setValuesForKeysWithDictionary:@{@"stringProp" : @"Same same!"}];`

[[[myDict allValues] mutableCopy] setValue:@"Another" forKeyPath:@"stringProp"];`

Or implement a category

@interface NSMutableDictionary (KVCForValues)

- (void)setValuesForValuesWithKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
- (void)setValue:(nullable id)value forValuesWithKeyPath:(NSString *)keyPath;

@end

@implementation NSMutableDictionary (KVCForValues)

- (void)setValuesForValuesWithKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues {
  [[[self allValues] mutableCopy] setValuesForKeysWithDictionary:keyedValues];
}

- (void)setValue:(id)value forValuesWithKeyPath:(NSString *)keyPath {
  [[[self allValues] mutableCopy] setValue:value forKeyPath:keyPath];
}

@end

And make use of it

[myDict setValuesForValuesWithKeysWithDictionary:@{@"stringProp" : @"Same same!"}];

[myDict setValue:@"Another" forValuesWithKeyPath:@"stringProp"];

This approach makes sense when you want to use KVC approach that is not possible with the accepted answer.


Concrete example

Assuming SomeClass is defined as follows

@interface SomeClass: NSObject

@property (nonatomic, strong) NSString *someProperty;
@property (nonatomic, assign) NSInteger anotherProperty;

@end

@implementation SomeClass

- (NSString *)description {
    return [NSString stringWithFormat:@"someProperty=%@, anotherProperty=%d", self.someProperty, (int)self.anotherProperty];
}

@end

Executing the following

SomeClass *value1 = [[SomeClass alloc] init];
value1.someProperty = @"aaa";
value1.anotherProperty = 111;

SomeClass *value2 = [[SomeClass alloc] init];
value2.someProperty = @"bbb";
value2.anotherProperty = 222;

SomeClass *value3 = [[SomeClass alloc] init];
value3.someProperty = @"ccc";
value3.anotherProperty = 333;

NSDictionary *someDictionary = @{@"key1": value1, @"key2": value2, @"key3": value3};

NSLog(@"%@", someDictionary);

Will produce the following output

key1 = "someProperty=aaa, anotherProperty=111";
key2 = "someProperty=bbb, anotherProperty=222";
key3 = "someProperty=ccc, anotherProperty=333";

After executing

[[[someDictionary allValues] mutableCopy] setValue:@"SameValue" forKeyPath:@"someProperty"];

NSLog(@"%@", someDictionary);

The output would be

key1 = "someProperty=SameValue, anotherProperty=111";
key2 = "someProperty=SameValue, anotherProperty=222";
key3 = "someProperty=SameValue, anotherProperty=333";
tonymontana
  • 5,728
  • 4
  • 34
  • 53
  • It seems you misunderstood the question. In my sample (for `NSDictionary`), I ask if I can set a *VALUE* to *ALL KEYS* in a flat dictionary by using KVC. Like, a Dict with keys and values: `[0: "0", 1: "1", 2: "2", 3: "3"]`, I'd like to make it `[0: "Same", 1: "Same", 2: "Same", 3: "Same"]`. Does this make sense to you? – Eddie Feb 21 '18 at 04:02
  • 1
    @Eddie That's exactly what the code above does. I've added a sample code. In any case, the NSDictionary's values in your comment should be of type `SomeClass` as in your question and not `NSString`. It won't work for `NSString` even with `NSMutableArray`. – tonymontana Feb 21 '18 at 07:54
  • That's a good explanation. However, it's impossible to set a value directly to the keys but need objects as a bridging and set values to the object's properties instead, am I correct? Like, it's not possible to set it as in my previous comment, is it? – Eddie Feb 21 '18 at 10:47
  • @Eddie Not possible – tonymontana Feb 21 '18 at 14:13