In Swift 3, how to convert a dictionary to Object? - swift

[I am new to Swift, I don't know is this possible or not, so please suggest me]
I have a dictionary (which is dynamic) like this:
let simpleHash = ["testA": "A", "testB": "B", "testC": "C"]
I want to convert this to an Object, so that I can access like:
simpleHash.testA // instead of simpleHash["testA"]
I have tried the below one, but it didn't help
let jsonData = try JSONSerialization.data(withJSONObject: simpleHash, options: .prettyPrinted)
let decoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
Can anyone please suggest me on this.
Thanks in advance!

Swift will need an explicitly declared variable for testA so you will not be able to be 100% dynamic. But, since you need to use the variable in code, it will be known at some point. Given this and in the spirit of minimizing the declaration constraints, you could define a class that uses the dictionary as its internal storage and exposes the key values as computed properties.
here's an example:
class DictionaryBased
{
var content:[String:Any]
init(_ dictionary:[String:Any])
{ content = dictionary }
func get<T>(_ key:String, _ defaultValue:T) -> T
{ return content[key] as? T ?? defaultValue }
func set<T>(_ key:String, _ value:T)
{ content[key] = value }
}
class SimpleHash:DictionaryBased
{}
With this, you can add computed properties as needed (and where needed) using extensions.
extension SimpleHash
{
var testA:String { get { return get("testA", "") } set { set("testA",newValue) } }
var testB:String { get { return get("testB", "") } set { set("testB",newValue) } }
// if variables are "read-only", you don't need the set { } part
var testC:String { get { return get("testC", "") } }
}
You can add variables that are typed or not and support optionals or, (as above) provide default values.
extension SimpleHash
{
var testD:Any? { get { return get("testD", nil) } set { set("testD",newValue) } }
var testE:String? { get { return get("testE", nil) } set { set("testE",newValue) } }
var testF:Date? { get { return get("testF", nil) } set { set("testE",newValue) } }
}
To use this "dictionary based" object, you would need to create an instance at some point and give it the dictionary's content:
let simpleHash = SimpleHash(["testA": "A", "testB": "B", "testC": "C"])
simpleHash.testA // "A"
simpleHash.testD // nil
Note that, this isn't going to be as efficient as using native properties and mapping the dictionary to each physical variable. On the other hand, it is a lot less code so. If the variables are not referenced often, the extra overhead may be an acceptable trade off for simplicity and flexibility.

A simple struct to hold your Dictionary values:
struct SimpleStruct {
// properties are Optional since they might not be matched
let testA: String?
let testB: String?
// this one has a default value
let testC: String
// init that takes a Dictionary
init(dictionary: [String:Any]) {
// set the Optional ones
self.testA = dictionary["testA"] as? String
self.testB = dictionary["testB"] as? String
// set the one with a default
self.testC = dictionary["testC"] as? String ?? "C"
}
}
let foo = SimpleStruct(dictionary: ["testA": "A", "testB": "B", "testC": "C"])
// force-unwrapping for brevity
// you should actually test before using
print(foo.testA!) // prints A
print(foo.testB!) // prints B
print(foo.testC) // prints C

Related

Swift, help iterating over keyPaths and setting values

I've found that it's a little easier to explain what I'm doing by giving too much context for why I'm trying to do it, sorry.
I'm currently trying to add an encryption service to my project. It's nothing that'll get published I think though and I've mostly got it working. The problem that I'm having is that I have my model like this
struct Entity {
// All types are examples though I think they will be all optionals.
var prop1: String?
var prop2: Int?
var prop3: Bool?
var encryptedData: [Keypath:EncryptedData]
static var encryptableKeyPaths: [WritableKeyPath<Entity, Any?>]
}
As an example for what's happening, I can get the encryptionService to take in prop1, create an EncryptedData and put it in the encryptedData dictionary. I can even get the keyPath for the property. I can encrypt all the data and decrypt it just fine and get all the values properly, so I don't need help with that. But I'm struggling with 3 issues.
Getting the KeyPaths to be WritableKeyPaths so I can write to them with the values I need.
Setting the properties to nil once the values are encrypted so I'm not storing extra data.
Setting the properties to their values once their decrypted.
All three of these issues seem to revolve around making the KeyPaths into WritableKeyPaths.
This is the closest attempt I've gotten so far. You can copy the following code right into a playground and run it and it should work. Except it'll crash at the end. There are a couple of issues here, I'm losing the type safety as I have to make all the property types Initializable? which isn't great. Also, see that the values are permanently wrapped. I can't figure out how to prevent that. I had to mark Optional as conforming to Initializable to make this work. Lastly, the variable allStoredProperties doesn't let me write to them. I'm not sure how to properly convert it to WritableKeyPath from PartialKeyPath.
import UIKit
protocol Initializable {}
extension String: Initializable {}
extension Int: Initializable {}
extension Bool: Initializable {}
extension Optional: Initializable {}
protocol KeyPathIterable {
associatedtype Model
init()
static var allKeyPaths: [WritableKeyPath<Model, Initializable?>] { get }
}
extension KeyPathIterable {
var keyPathReadableFormat: [String: Initializable] {
var description: [String: Initializable] = [:]
let mirror = Mirror(reflecting: self)
for case let (label?, value) in mirror.children {
description[label] = (value as! Initializable)
}
return description
}
static var allStoredProperties: [PartialKeyPath<Self>] {
var members: [PartialKeyPath<Self>] = []
let instance = Self()
for (key, _) in instance.keyPathReadableFormat {
members.append(\Self.keyPathReadableFormat[key])
}
return members
}
static func setValue<Self: KeyPathIterable, T: Initializable>(on root: inout Self,
at keyPath: WritableKeyPath<Self, Initializable?>,
withValue value: T?) throws {
root[keyPath: keyPath] = value
}
}
struct Foo: KeyPathIterable {
typealias Model = Foo
var prop1: Initializable? // I want this to be String?
var prop2: Initializable? // I want this to be Int?
var prop3: Initializable? // I want this to be Bool?
init() {
self.prop1 = nil
self.prop2 = nil
self.prop3 = nil
}
static var allKeyPaths: [WritableKeyPath<Foo, Initializable?>] {
return [\Model.prop1, \Model.prop2, \Model.prop3]
}
}
var foo = Foo()
foo.prop1 = "Bar"
foo.prop2 = 1
foo.prop3 = true
print(foo.prop1 as Any)
let keyPath = \Foo.prop1
foo[keyPath: keyPath] = "Baz"
print(foo.prop1 as Any)
for path in Foo.allStoredProperties {
print("-=-=-")
print(path)
}
print("-=-=-=-=-=-=-=-")
do {
try Foo.setValue(on: &foo, at: keyPath, withValue: "BazBar" as Initializable?)
} catch {
print("Should never fail")
}
print(foo.prop1 as Any) // Returns Optional(Optional("BarBaz")) - I want this to be all the way unwrapped.
print("--------------")
let values1: [Initializable] = ["Hello World", 100, false]
do {
for (path, value) in zip(Foo.allKeyPaths, values1) {
try Foo.setValue(on: &foo,
at: path,
withValue: value as Initializable?)
}
} catch {
print("Success?")
}
print(foo.prop1 as Any)
print(foo.prop2 as Any)
print(foo.prop3 as Any)
print("----====----====----")
let values2: [Initializable] = ["Howdy", 0, false]
do {
for (path, value) in zip(Foo.allStoredProperties, values2) {
try Foo.setValue(on: &foo,
at: path as! WritableKeyPath<Foo, Initializable?>,
withValue: value as Initializable?)
}
} catch {
print("Always fails")
}
print("=-=-=-=-=-=-=-=")
print(foo)
I've looked all over google and youtube and everywhere and I can't seem to get this to work. I'm open to a different architecture if that work accomplish my goals better. Just a little frustrated. Thanks for your help.

Exposing dictionary in Swift property wrappers

I have an internal dictionary that I don't want to expose to the user. Instead, I expose only certain values using properties, like this:
public var artist: String? {
get {
return items["artist"]
}
set {
items["artist"] = newValue
}
}
//...so on for another 20 or so items
As you can imagine, this ends up getting repeated quite a lot. I was thinking that property wrappers would be a nice way to clean this up - however, it's not possible to pass items directly to the wrapper, since property wrappers are created before init (so self would not be accessible).
Is there a way around this, or is this just one of the limitations of propertyWrappers?
You could build a generic solution. I did one, but you can probably improve it:
class PropertyWrapper {
private var items: [String: Any] = ["artist": "some dude"]
enum Key: String {
case artist
}
func getItem<T: Any>(key: Key) -> T {
guard let item = items[key.rawValue] as? T else {
preconditionFailure("wrong type asked for")
}
return item
}
func setItem(value: Any, key: Key) {
items[key.rawValue] = value
}
}
class GetValueClass {
func getValue() {
let wrapper = PropertyWrapper()
let value: String = wrapper.getItem(key: .artist)
}
}
class SetValueClass {
func setValue() {
let wrapper = PropertyWrapper()
wrapper.setItem(value: "some", key: .artist)
}
}

Get all key paths from a struct in Swift 4

Let's say I have that struct:
struct MyStruct {
let x: Bool
let y: Bool
}
In Swift 4 we can now access it's properties with the myStruct[keyPath: \MyStruct.x] interface.
What I need is a way to access all it's key paths, something like:
extension MyStruct {
static func getAllKeyPaths() -> [WritableKeyPath<MyStruct, Bool>] {
return [
\MyStruct.x,
\MyStruct.y
]
}
}
But, obviously, without me having to manually declare every property in an array.
How can I achieve that?
DISCLAIMER:
Please note that the following code is for educational purpose only and it should not be used in a real application, and might contains a lot of bugs/strange behaviors if KeyPath are used this way.
Answer:
I don't know if your question is still relevant today, but the challenge was fun :)
This is actually possible using the mirroring API.
The KeyPath API currently doesn't allow us to initialize a new KeyPath from a string, but it does support dictionary "parsing".
The idea here is to build a dictionary that will describe the struct using the mirroring API, then iterate over the key to build the KeyPath array.
Swift 4.2 playground:
protocol KeyPathListable {
// require empty init as the implementation use the mirroring API, which require
// to be used on an instance. So we need to be able to create a new instance of the
// type.
init()
var _keyPathReadableFormat: [String: Any] { get }
static var allKeyPaths: [KeyPath<Foo, Any?>] { get }
}
extension KeyPathListable {
var _keyPathReadableFormat: [String: Any] {
let mirror = Mirror(reflecting: self)
var description: [String: Any] = [:]
for case let (label?, value) in mirror.children {
description[label] = value
}
return description
}
static var allKeyPaths: [KeyPath<Self, Any?>] {
var keyPaths: [KeyPath<Self, Any?>] = []
let instance = Self()
for (key, _) in instance._keyPathReadableFormat {
keyPaths.append(\Self._keyPathReadableFormat[key])
}
return keyPaths
}
}
struct Foo: KeyPathListable {
var x: Int
var y: Int
}
extension Foo {
// Custom init inside an extension to keep auto generated `init(x:, y:)`
init() {
x = 0
y = 0
}
}
let xKey = Foo.allKeyPaths[0]
let yKey = Foo.allKeyPaths[1]
var foo = Foo(x: 10, y: 20)
let x = foo[keyPath: xKey]!
let y = foo[keyPath: yKey]!
print(x)
print(y)
Note that the printed output is not always in the same order (probably because of the mirroring API, but not so sure about that).
After modifying rraphael's answer I asked about this on the Swift forums.
It is possible, discussion here:
Getting KeyPaths to members automatically using Mirror
Also, the Swift for TensorFlow team has this already built in to Swift for TensorFlow, which may make its way to pure swift:
Dynamic property iteration using key paths
I propose my solution. It has the advantage of dealing correctly with #Published values when using the Combine framework.
For the sake of clarity, it is a simplified version of what I have really. In the full version, I pass some options to the Mirror.allKeyPaths() function to change behaviour ( To enumerate structs and/or classes properties in sub-dictionaries for example ).
The first Mirror extension propose some functions to simplify properties enumeration.
The second extension implements the keyPaths dictionaries creation, replacing
#Published properties by correct name and value
The last part is the KeyPathIterable protocol, that add enumeration
capability to associated object
swift
// MARK: - Convenience extensions
extension String {
/// Returns string without first character
var byRemovingFirstCharacter: String {
guard count > 1 else { return "" }
return String(suffix(count-1))
}
}
// MARK: - Mirror convenience extension
extension Mirror {
/// Iterates through all children
static func forEachProperty(of object: Any, doClosure: (String, Any)->Void) {
for (property, value) in Mirror(reflecting: object).children where property != nil {
doClosure(property!, value)
}
}
/// Executes closure if property named 'property' is found
///
/// Returns true if property was found
#discardableResult static func withProperty(_ property: String, of object: Any, doClosure: (String, Any)->Void) -> Bool {
for (property, value) in Mirror(reflecting: object).children where property == property {
doClosure(property!, value)
return true
}
return false
}
/// Utility function to determine if a value is marked #Published
static func isValuePublished(_ value: Any) -> Bool {
let valueTypeAsString = String(describing: type(of: value))
let prefix = valueTypeAsString.prefix { $0 != "<" }
return prefix == "Published"
}
}
// MARK: - Mirror extension to return any object properties as [Property, Value] dictionary
extension Mirror {
/// Returns objects properties as a dictionary [property: value]
static func allKeyPaths(for object: Any) -> [String: Any] {
var out = [String: Any]()
Mirror.forEachProperty(of: object) { property, value in
// If value is of type Published<Some>, we transform to 'regular' property label and value
if Self.isValuePublished(value) {
Mirror.withProperty("value", of: value) { _, subValue in
out[property.byRemovingFirstCharacter] = subValue
}
} else {
out[property] = value
}
}
return out
}
}
// MARK: - KeyPathIterable protocol
protocol KeyPathIterable {
}
extension KeyPathIterable {
/// Returns all object properties
var allKeyPaths: [String: Any] {
return Mirror.allKeyPaths(for: self)
}
}

Converting a rawValue into a string in Swift

Apple has made changes from Swift 3 to 4. When I run the following code:
let metadata = [ PDFDocumentAttribute.titleAttribute,
PDFDocumentAttribute.authorAttribute,
PDFDocumentAttribute.subjectAttribute,
PDFDocumentAttribute.creatorAttribute,
PDFDocumentAttribute.producerAttribute,
PDFDocumentAttribute.creationDateAttribute,
PDFDocumentAttribute.modificationDateAttribute,
PDFDocumentAttribute.keywordsAttribute ]
if var attributes = pdfDoc.documentAttributes {
for (index, value) in metadata.enumerated() {
if attributes[value] != nil {
print("\(metadata[index])): \(String(describing: attributes[value]!))")
} else {
print("\(metadata[index]): nil")
}
}
I now get: PDFDocumentAttribute(_rawValue: Title) instead of "Title", which I got before as the value of metadata[index].
How do I get rid of the rawValue stuff?
The PDFDocumentAttribute type has a property called rawValue that contains the old string value. So you can say
print("\(metadata[index].rawValue): \(String(describing: attributes[value]!))")
As an aside, instead of force-unwrapping the attribute you can use an if let, as in
if let attr = attributes[value] {
print("\(metadata[index].rawValue): \(attr)")
} else {
print("\(metadata[index].rawValue): nil")
}
If you add this extension:
extension PDFDocumentAttribute: CustomStringConvertible {
public var description: String {
return self.rawValue
}
}
Now you can just do:
// Forcing the downcast has little risk here
// but you may want to use `as?` and test for the optional instead
let attributes = pdfDoc.documentAttributes as! [PDFDocumentAttribute:Any]
for meta in metadata {
print("\(meta): \(attributes[meta] ?? "nil")")
}
Note that you can also do:
for attribute in attributes {
print("\(attribute.key): \(attribute.value)")
}
Which will just print out the attributes that exist on the document.

Dictionary of dictionaries in Swift

I'd like to build a dictionary of dictionaries. In Swift how do I declare a dictionary with a key of a String and the value of a dictionary of this same type? I need to be able to have potentially infinite nests. (Kind of like building a tree using nodes. Except it's not a tree, it's a dictionary.)
I tried using AnyObject, but get a conversion error:
var node1: Dictionary<String, AnyObject?> = ["foo" : nil]
var node2: Dictionary<String, AnyObject?> = ["bar" : node1] // ERROR: Cannot convert value of type 'Dictionary<String, AnyObject?>' (aka 'Dictionary<String, Optional<AnyObject>>') to expected dictionary value type 'Optional<AnyObject>'
Is there a type-safe way of doing this (i.e., not using AnyObject?)
You can achieve something like this with a nice API and type safety in swift by using a struct and an enumeration.
enum RecursiveDictValue<KeyType: Hashable, ValueType> {
case Value(ValueType)
case Dict(RecursiveDict<KeyType, ValueType>)
}
struct RecursiveDict<KeyType: Hashable, ValueType> {
typealias OwnType = RecursiveDict<KeyType, ValueType>
private var dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]
init() {
dict = [:]
}
init(dict: [KeyType: RecursiveDictValue<KeyType, ValueType>]) {
self.dict = dict
}
// this ensures that we can safely chain subscripts
subscript(key: KeyType) -> OwnType {
get {
switch dict[key] {
case let .Dict(dict)?:
return dict
default:
return RecursiveDict<KeyType, ValueType>()
}
}
set(newValue) {
dict[key] = .Dict(newValue)
}
}
subscript(key: KeyType) -> ValueType? {
get {
switch dict[key] {
case let .Value(value)?:
return value
default:
return nil
}
}
set(newValue) {
if let newValue = newValue {
dict[key] = RecursiveDictValue<KeyType, ValueType>.Value(newValue)
} else {
dict[key] = nil
}
}
}
}
This works quite nicely (note that you need to help swift with the types though):
var dict = RecursiveDict<String, Int>(dict: ["value":.Value(1),
"dict":.Dict(RecursiveDict<String, Int>(dict: ["nestedValue": .Value(2)]))])
if let value: Int = dict["value"] {
print(value) // prints 1
}
if let value: Int = dict["dict"]["nestedValue"] {
print(value) // prints 2
}
It also fails as intended when you do stuff that can't work.
if let value: Int = dict["dict"] {
print(value) // is not executed
}
if let value: Int = dict["dict"]["nestedDict"]["nestedValue"] {
print(value) // is not executed
}
And you can even set values in nested dictionaries that haven't been created yet!:
dict["dict"]["nestedDict2"]["nestedValue"] = 3
if let value: Int = dict["dict"]["nestedDict2"]["nestedValue"] {
print(value) // prints 3
}
I was working with firebase, and i needed to achieve an structure similar to this:
["llave3": ["hola": "", "dos": ""], "llave1": ["hola": "", "dos": ""], "llave2": ["hola": "", "dos": ""]]
This is a nested dictionary, or a dictionary of dictionaries. I achieve this by simply doing this:
var array = ["llave1", "llave2","llave3"]
var dictOfDictionarys = [String : [String : String]] ()
for items in array {
dictOfDictionarys[items] = ["hola":"","dos":""]
}
Very less info.. and you mean infinite nested dictionaries? I dont think so..
func returnDict() -> Dictionary<String, AnyObject> {
return ["Got You" : returnDict()]
}
var x : Dictionary<String, AnyObject> = ["GotYou" : returnDict()]
Just saying, nothing better can happen to this other than a crash
this is a case of infinite recursion. When you have infinite dictionaries, it doesnt mean that it is going to run forever. It means that it is going to run till your device runs out of memory. A call to function returnDict, calls returnDict, which again calls returnDict and so on.
A recursion is basically adding a method onto the stack of pre-existing stack of methods in memory.. this can happen until the stack overflows. Hence, stackOverFlow
let node1: Dictionary<String, AnyObject!> = ["foo" : nil]
var node2 = ["bar" : node1]
Playground approves of it
The reason is that like in Objective-C values in the Dictionary type must be non-optional.
It's not very useful anyway because in Swift assigning a nil value to a key removes the key.
var node1: Dictionary<String, AnyObject> = ["foo" : "Hello"]
var node2: Dictionary<String, AnyObject> = ["bar" : node1]