Info.plist Dictionary to Dictionary of type Enum:String - swift

I'm trying to take a dictionary from my Info.plist and save it as a Dictionary of type Enum: String
To better explain, I'm trying to convert the urlDict below to be a Dictionary of type but keep getting fatal error.
I can't figure out why
let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> does not work
The enum has a raw type of String and has a case for keyOne.
enum URLKeys: String {
case keyOne = "keyOne"
}
var keysDictionary = Dictionary<String, Any>()
keysDictionary["keyOne"] = "abc"
var urlDict = Dictionary<String, Any>()
urlDict["keys"] = keysDictionary
guard let enumDict = urlDict["keys"] as? Dictionary<URLKeys, String> else {
fatalError()
}

Use forEach and create a URLKeys for each key and cast each value to string
var enumDict:[URLKeys: String] = [:]
keysDictionary.forEach {
if let key = URLKeys(rawValue: $0.0), let value = $0.1 as? String {
enumDict[key] = value
}
}

Related

how to get single variable name from struct

I have a core data framework to handle everything you can do with coredata to make it more cooperateable with codable protocol. Only thing i have left is to update the data. I store and fetch data by mirroring the models i send as a param in their functions. Hence i need the variable names in the models if i wish to only update 1 specific value in the model that i request.
public func updateObject(entityKey: Entities, primKey: String, newInformation: [String: Any]) {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityKey.rawValue)
do {
request.predicate = NSPredicate.init(format: "\(entityKey.getPrimaryKey())==%#", primKey)
let fetchedResult = try delegate.context.fetch(request)
print(fetchedResult)
guard let results = fetchedResult as? [NSManagedObject],
results.count > 0 else {
return
}
let key = newInformation.keys.first!
results[0].setValue(newInformation[key],
forKey: key)
try delegate.context.save()
} catch let error {
print(error.localizedDescription)
}
}
As you can see the newInformation param contains the key and new value for the value that should be updated. However, i dont want to pass ("first": "newValue") i want to pass spots.first : "newValue"
So if i have a struct like this:
struct spots {
let first: String
let second: Int
}
How do i only get 1 name from this?
i've tried:
extension Int {
var name: String {
return String.init(describing: self)
let mirror = Mirror.init(reflecting: self)
return mirror.children.first!.label!
}
}
I wan to be able to say something similar to:
spots.first.name
But can't figure out how
Not sure that I understood question, but...what about this?
class Spots: NSObject {
#objc dynamic var first: String = ""
#objc dynamic var second: Int = 0
}
let object = Spots()
let dictionary: [String: Any] = [
#keyPath(Spots.first): "qwerty",
#keyPath(Spots.second): 123,
]
dictionary.forEach { key, value in
object.setValue(value, forKeyPath: key)
}
print(object.first)
print(object.second)
or you can try swift keypath:
struct Spots {
var first: String = ""
var second: Int = 0
}
var spots = Spots()
let second = \Spots.second
let first = \Spots.first
spots[keyPath: first] = "qwerty"
spots[keyPath: second] = 123
print(spots)
however there will be complex (or impossible) problem to solve if you will use dictionary:
let dictionary: [AnyKeyPath: Any] = [
first: "qwerty",
second: 123
]
you will need to cast AnyKeyPath back to WritableKeyPath<Root, Value> and this seems pretty complex (if possible at all).
for path in dictionary.keys {
print(type(of: path).rootType)
print(type(of: path).valueType)
if let writableKeyPath = path as? WritableKeyPath<Root, Value>, let value = value as? Value { //no idea how to cast this for all cases
spots[keyPath: writableKeyPath] = value
}
}

Adding nested dictionary causes JSONSerialization to return nil

I have the following structure that is used to pass JSON data to a REST endpoint. Originally the object contained only one level of key-value pairs. In that scenario, serializing to a JSON object worked properly.
Now I need to add a dictionary as a parameter, which should create a nested dictionary in the resulting JSON. However, adding the nested dictionary causes JSONSerialization to return nil.
Code:
struct ServicePayload:Codable {
private var name:String
private var type:String
private var deviceId:String
private var clientType:String
private var appInstanceId:String
private var version:String
private var addParams:[String:String] // causes failure
init(name:String, type:String, version:String, params:[String:String]) {
self.name = name
self.type = type
self.deviceId = Constants.Device.identifier!
self.version = version
self.clientType = "1"
self.appInstanceId = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
self.addParams = params
}
// json mapper
private enum CodingKeys:String, CodingKey {
case name = "name"
case type = "contentTypes"
case deviceId = "x-DeviceId"
case clientType = "x-ClientType"
case appInstanceId = "x-InstanceId"
case version = "version"
case addParams = "optionalParams"
}
func getJsonObject() -> [String:String]? {
do {
let encoded = try JSONEncoder().encode(self)
if let json = try JSONSerialization.jsonObject(with: encoded, options: []) as? [String : String] {
return json
}
} catch (let error) {
print("Error building JSON: \(error.localizedDescription)")
}
return nil
}
}
Without the the addParams field, the JSONSerialization works as expected. When I add the addParams field, which adds a nested dictionary to the object, the JSONSerialization fails and returns nil.
Can anyone give me a clue as to why I can't add a nested dictionary in this scenario?
Thanks!
It fails as one key (here it's the added addParams ) 's value isn't a String so the cast
as? [String : String] // causes failure
Won't occur , hence a nil json , so Replace
if let json = try JSONSerialization.jsonObject(with: encoded, options: [])
as? [String : String] {
with
if let json = try JSONSerialization.jsonObject(with: encoded, options: [])
as? [String : Any] {
Any encapsulates String and [String:String]

Can't extract the dictionary as [String : Any] from vapor request context

I'm new to server side swift. I'm using vapor for server side swift. In vapor request I need to get JSON as [String: Any] to check a data type of the value like String, Int or Float. But in request the I can't find the exact data type of the value.
drop.post("post") { (request) -> ResponseRepresentable in
guard let name = request.data["value"]?.string else {
throw Abort.badRequest
}
return value
}
In above method, it directly converts and returns the value as String. I need to check it is a String or Int (some other data types too). I can't check by let condition which is given as below.
guard let name = data["value"] as? String else {
\\do something
}
I need to check it is a String or Int (some other data types too). If anyone has the solution, please let me know.
if you try to get Type of data using a type(of:) function, in result you will get optional any like this.
let dic = ["key":"string"] as [String : Any]
let str = dic["key"] //"string"
type(of: str) //Optional<Any>.Type
you have to check with " if let " for all case.
let dic = ["key":"string"] as [String : Any]
if let str = dic["key"] as? String {
print("String value")
} else if let intvalue = dic["key"] as? Int {
print("Int value")
} else if let boolvalue = dic["key"] as? Bool {
print("Bool value")
}
Hope it will help you
Since you're accessing the JSON, I'd do it like this.
guard let json = request.json else {
throw ...
}
if let string = json.string {
// JSON is a string
} else if let object = json.object {
// JSON is a [String: JSON]
}
// continue unwrapping for different data types
I wouldn't recommend using the type(of:) function for this purpose.

Is there a way to use guard statements more concisely?

I'm using Gloss for my JSON instantiation. Here is a sample class:
public class MyObj: Decodable
{
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let contact_city : String
let contact_state : String
let contact_zip : String
let points : Int
// Deserialization
required public init?(json: JSON)
{
guard let id_user : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_addr1 : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_city : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_state : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_zip : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let points : Int = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
self.id_user = id_user
self.contact_addr1 = contact_addr1
self.contact_addr2 = "somekey" <~~ json
self.contact_city = contact_city
self.contact_state = contact_state
self.contact_zip = contact_zip
self.contact_points = points
}
}
I have a lot of model classes. Hundreds of members between them. Writing a multi-line guard statement for each one really junks up my code. Is there any way I can encapsulate the guard functionality into something more concise? Maybe a function or something like:
shortGuard("memberName", "jsonKey")
Maybe there is a way to guard against an array of string keys?
There are a huge variety of ways to accomplish this. They all boil down to writing a wrapper function to map your keys to values. Here are a couple quick examples I thought of, but as I say there are many ways to do this depending on what you're after:
enum JSONError: Error {
case keyNotFound(String)
}
extension JSON {
func values<T>(for keys: [String]) throws -> [T] {
var values = [T]()
for key in keys {
guard let value: T = key <~~ self else {
throw JSONError.keyNotFound(key)
}
values.append(value)
}
return values
}
func values<T>(for keys: [String], closure: ((_ key: String, _ value: T) -> Void)) throws {
for key in keys {
guard let value: T = key <~~ self else {
throw JSONError.keyNotFound(key)
}
closure(key, value)
}
}
}
The first validates all keys before you can use any of them and will throw if one isn't present. You'd use it like so:
do {
let keys = ["foo", "bar"]
// The type of the values constant is important.
// In this example we're saying look for values of type Int.
let values: [Int] = try json.values(for: keys)
for (index, key) in keys.enumerated() {
print("value for \(key): \(values[index])")
}
} catch JSONError.keyNotFound(let key) {
assertionFailure("key not found \(key)")
}
The second one will pass back key, value pairs to a closure as they appear in your keys array and will throw at the first one it finds that doesn't exist.
do {
let keys = ["foo", "bar"]
// The type of the closure's value argument is important.
// In this example we're saying look for values of type String.
try json.values(for: keys) { (key, value: String) in
print("value for key \(key) is \(value)")
}
} catch JSONError.keyNotFound(let key) {
assertionFailure("key not found \(key)")
}
Using the first version in an init?() function for your class, we have something like this:
public struct MyObj: Decodable {
public let id_user : String
public let contact_addr1 : String
public let contact_addr2 : String?
public let points : Int
public init?(json: S) {
do {
let stringKeys = ["id_user", "contact_addr1"]
let stringValues: [String] = try json.values(for: stringKeys)
id_user = stringValues[0]
contact_addr1 = stringValues[1]
// this isn't required, so just extract with no error if it fails
contact_addr2 = "contact_addr2" <~~ json
let intKeys = ["points"]
let intValues: [Int] = try json.values(for: intKeys)
points = intValues[0]
} catch JSONError.keyNotFound(let key) {
assertionFailure("key \(key) not found in JSON")
return nil
} catch {
return nil
}
}
}
I have not used Gloss, and it mostly seems to be unnecessary considering that it is simple enough to parse JSON safely without needing an extra library, or using unfamiliar syntax.
Option 1:
You can group the optional unwrapping in a single guard statement.
Example:
public struct MyObj {
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let points : Int
public init?(json: Any) {
guard
let entities = json as? [String : Any],
let id_user = entities["some key"] as? String,
let contact_addr1 = entities["some key"] as? String,
let points = entities["some key"] as? Int
else {
assertionFailure("...")
return nil
}
self.id_user = id_user
self.contact_addr1 = contact_addr1
self.contact_addr2 = entities["some key"] as? String
self.contact_points = points
}
}
Option 2:
Another approach would be to eliminate the guard statements altogether, and let the parser throw an error during parsing, and use an optional try to convert the result to nil.
Example:
// Helper object for parsing values from a dictionary.
// A similar pattern could be used for arrays. i.e. array.stringAt(10)
struct JSONDictionary {
let values: [String : Any]
init(_ json: Any) throws {
guard let values = json as? [String : Any] else {
throw MyError.expectedDictionary
}
self.values = values
}
func string(_ key: String) throws -> String {
guard let value = values[key] as? String else {
throw MyError.expectedString(key)
}
return value
}
func integer(_ key: String) throws -> Int {
guard let value = values[key] as? Int else {
throw MyError.expectedInteger(key)
}
return value
}
}
Parser:
public struct MyObj {
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let points : Int
public init(json: Any) throws {
// Instantiate the helper object.
// Ideally the JSONDictionary would be passed by the caller.
let dictionary = try JSONDictionary(json),
self.id_user = try dictionary.string("some key"),
self.contact_addr1 = try dictionary.string("some key"),
self.points = try dictionary.integer("some key")
// Results in an optional if the string call throws an exception
self.contact_addr2 = try? dictionary.string("some key")
}
}
Usage:
// Instantiate MyObj from myJSON.
// myObject will be nil if parsing fails.
let myObject = try? MyObj(json: myJSON)

Reflection in swift 2

I have a class User:
import UIKit
import ObjectMapper
class User: NSObject, CustomStringConvertible, Mappable {
var FirstName: NSString! ;
var LastName: NSString! ;
required init?(_ map: Map){
}
func mapping(map: Map) {
FirstName <- map["FirstName"]
LastName <- map["LastName"]
}
override var description:String {
var s:String=""
//USE REFLECTION TO GET NAME AND VALUE OF DATA MEMBERS
for var index=1; index<reflect(self).count; ++index {
s += (reflect(self)[index].0 + ": "+reflect(self)[index].1.summary+"\t")
}
return s
}
}
In swift 1.2, I was using reflect() method to get array of all the data members with their names and values.
Now, after I have updated to swift 2, I am getting the following error:
'reflect' is unavailable: call the 'Mirror(reflecting:)' initializer
With some trials, I was able to get the count of data members by this: Int(Mirror(reflecting: self).children.count), but still, I am unable to get the member name and its value.
I have looked into the following resources:
https://netguru.co/blog/reflection-swift
http://nshipster.com/mirrortype/
UPDATE
I have found the an answer here: https://stackoverflow.com/a/32846514/4959077. But this doesn't tell how to find out the type of reflected value. If the value is int and we parse it into String then it gives error.
You may access the reflected attribute "label" name, value and type as follows:
let mirror = Mirror(reflecting: SomeObject)
var dictionary = [String: Any]()
for child in mirror.children {
guard let key = child.label else { continue }
let value: Any = child.value
dictionary[key] = value
switch value {
case is Int: print("integer = \(anyValue)")
case is String: print("string = \(anyValue)")
default: print("other type = \(anyValue)")
}
switch value {
case let i as Int: print("• integer = \(i)")
case let s as String: print("• string = \(s)")
default: print("• other type = \(anyValue)")
}
if let i = value as? Int {
print("•• integer = \(i)")
}
}
Note: per the question followup, three approaches to determine the type of the reflected value are shown.
I have a solution that finds the name and type of a property given any class that inherits from NSObject.
I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,
In short you can do something like this (but really check out the code Github):
public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
var count = UInt32()
guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
var types: Dictionary<String, Any> = [:]
for i in 0..<Int(count) {
guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
let type = getTypeOf(property: property)
types[name] = type
}
free(properties)
return types
}