Using Key-Value Programming (Kvp) with Swift

Using key-value programming (KVP) with Swift

The array will actually respond to valueForKeyPath function - you just need to cast the array to AnyObject so that the compiler doesn't complain. As follows:

var max = (numbers as AnyObject).valueForKeyPath("@max.self") as Double

or even, for a union of objects:

(labels as AnyObject).valueForKeyPath("@unionOfObjects.text")

If labels above is a collection of labels, the above will return an array of all the strings of the text property of each label.

It is also equivalent to the following:

(labels as AnyObject).valueForKey("text")

... just as it is in Objective-C :)

How to use a Key Value Observer in swift?

After you get the image make a var with a didSet and that var save the imaged
ex

var image : UIImage{//or what type your image is,Maby NSData,but I'm not sure
didSet{
// adjustingExposure and adjustingWhiteBalance
}

and then you save it EX:

func grabImage(){//is an example IDK your code,I say that this func captured the imagedate
image = imageThatYouTook
//then save the image data from the image var
}

Objective C - KeyValuePair class?

So basically like a hashmap, right?

Use NSMutableDictionary

Example from here:

NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; 

// Add objects to a dictionary indexed by keys

[dictionary setObject:@"A Book about the Letter A" forKey:@"A"];
[dictionary setObject:@"A Book about the Letter B" forKey:@"B"];
[dictionary setObject:@"A Book about the Letter C" forKey:@"C"];

// Retrieve an object from a dictionary with a key

NSLog([dictionary objectForKey:@"B"]);

// Release a dictionary

[dictionary release];

Swift semantics regarding dictionary access

dict["key"]?.change() // Copy

is semantically equivalent to:

if var value = dict["key"] {
value.change() // Copy
dict["key"] = value
}

The value is pulled out of the dictionary, unwrapped into a temporary, mutated, and then placed back into the dictionary.

Because there's now two references to the underlying buffer (one from our local temporary value, and one from the COWStruct instance in the dictionary itself) – we're forcing a copy of the underlying Buffer instance, as it's no longer uniquely referenced.

So, why doesn't

array[0].change() // No Copy

do the same thing? Surely the element should be pulled out of the array, mutated and then stuck back in, replacing the previous value?

The difference is that unlike Dictionary's subscript which comprises of a getter and setter, Array's subscript comprises of a getter and a special accessor called mutableAddressWithPinnedNativeOwner.

What this special accessor does is return a pointer to the element in the array's underlying buffer, along with an owner object to ensure that the buffer isn't deallocated from under the caller. Such an accessor is called an addressor, as it deals with addresses.

Therefore when you say:

array[0].change()

you're actually mutating the actual element in the array directly, rather than a temporary.

Such an addressor cannot be directly applied to Dictionary's subscript because it returns an Optional, and the underlying value isn't stored as an optional. So it currently has to be unwrapped with a temporary, as we cannot return a pointer to the value in storage.

In Swift 3, you can avoid copying your COWStruct's underlying Buffer by removing the value from the dictionary before mutating the temporary:

if var value = dict["key"] {
dict["key"] = nil
value.change() // No Copy
dict["key"] = value
}

As now only the temporary has a view onto the underlying Buffer instance.

And, as @dfri points out in the comments, this can be reduced down to:

if var value = dict.removeValue(forKey: "key") {
value.change() // No Copy
dict["key"] = value
}

saving on a hashing operation.

Additionally, for convenience, you may want to consider making this into an extension method:

extension Dictionary {
mutating func withValue<R>(
forKey key: Key, mutations: (inout Value) throws -> R
) rethrows -> R? {
guard var value = removeValue(forKey: key) else { return nil }
defer {
updateValue(value, forKey: key)
}
return try mutations(&value)
}
}

// ...

dict.withValue(forKey: "key") {
$0.change() // No copy
}

In Swift 4, you should be able to use the values property of Dictionary in order to perform a direct mutation of the value:

if let index = dict.index(forKey: "key") {
dict.values[index].change()
}

As the values property now returns a special Dictionary.Values mutable collection that has a subscript with an addressor (see SE-0154 for more info on this change).

However, currently (with the version of Swift 4 that ships with Xcode 9 beta 5), this still makes a copy. This is due to the fact that both the Dictionary and Dictionary.Values instances have a view onto the underlying buffer – as the values computed property is just implemented with a getter and setter that passes around a reference to the dictionary's buffer.

So when calling the addressor, a copy of the dictionary's buffer is triggered, therefore leading to two views onto COWStruct's Buffer instance, therefore triggering a copy of it upon change() being called.

I have filed a bug over this here. (Edit: This has now been fixed on master with the unofficial introduction of generalised accessors using coroutines, so will be fixed in Swift 5 – see below for more info).


In Swift 4.1, Dictionary's subscript(_:default:) now uses an addressor, so we can efficiently mutate values so long as we supply a default value to use in the mutation.

For example:

dict["key", default: COWStruct()].change() // No copy

The default: parameter uses @autoclosure such that the default value isn't evaluated if it isn't needed (such as in this case where we know there's a value for the key).


Swift 5 and beyond

With the unofficial introduction of generalised accessors in Swift 5, two new underscored accessors have been introduced, _read and _modify which use coroutines in order to yield a value back to the caller. For _modify, this can be an arbitrary mutable expression.

The use of coroutines is exciting because it means that a _modify accessor can now perform logic both before and after the mutation. This allows them to be much more efficient when it comes to copy-on-write types, as they can for example deinitialise the value in storage while yielding a temporary mutable copy of the value that's uniquely referenced to the caller (and then reinitialising the value in storage upon control returning to the callee).

The standard library has already updated many previously inefficient APIs to make use of the new _modify accessor – this includes Dictionary's subscript(_:) which can now yield a uniquely referenced value to the caller (using the deinitialisation trick I mentioned above).

The upshot of these changes means that:

dict["key"]?.change() // No copy

will be able to perform an mutation of the value without having to make a copy in Swift 5 (you can even try this out for yourself with a master snapshot).

Deserializing key value pair into list

I recommend custom types if that's possible. Here's a console app you can copy and paste that shows you what I'm referring to using the information you've provided. It uses the well known and highly recommended Newtonsoft.Json nuget package.

Code:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace Question_Answer_Console_App
{
public class Program
{
public const string JsonResultString = @"{
""status"": ""SUCCESS"",
""message"": ""something"",
""data"": {
""trade_origin_iso3country"": ""GBR"",
""countries"": {
""ARM"": ""Armenia"",
""BLR"": ""Belarus "",
""DNK"": ""Denmark"",
""GBR"": ""United Kingdom"",
""MCO"": ""Monaco""
}
}
}";
[STAThread]
static void Main(string[] args)
{
var jsonResult = JsonConvert.DeserializeObject<JsonResult>(JsonResultString);

foreach (var keyValue in jsonResult.Data.Countries)
Console.WriteLine($"{keyValue.Key} : {keyValue.Value}");

Console.Read();
}
}

public class JsonResult
{
public string Status { get; set; }
public string Message { get; set; }
public JsonData Data { get; set; }
}

public class JsonData
{
[JsonProperty("trade_origin_iso3country")]
public string TradeOriginIso3country { get; set; }
public Dictionary<string, string> Countries { get; set; }
}
}

Outputs:

ARM : Armenia
BLR : Belarus
DNK : Denmark
GBR : United Kingdom
MCO : Monaco

How to create a two string array from a sequence of key-value pairs (tuple) in swift

As already mentioned, since Xcode 9, the Swift Standard Library provides a handy Dictionary initializer for such cases:

init<S>(uniqueKeysWithValues keysAndValues: S) 
where S: Sequence, S.Element == (Key, Value)

Creates a new dictionary from the key-value pairs in the given sequence.

This might be difficult to read if aren't too familiar with Swift generics ;) Nevertheless, the usage is pretty straightforward:

let cityNames = ["Riyadh", "Mecca", "Sultanah", "Buraydah", "Al Qarah"]
let nearestDistances = [84.24, 41.37, 45.37, 57.96, 78.78]

let dict = Dictionary(uniqueKeysWithValues: zip(cityNames, nearestDistances))
print(dict)

prints:

[  
"Buraydah": 57.96,
"Al Qarah": 78.78,
"Mecca": 41.37,
"Riyadh": 84.24,
"Sultanah": 45.37
]

Finally, the resulting dictionary type is what you would expect:

print(type(of: dict)) // Dictionary<String, Double>


Related Topics



Leave a reply



Submit