Use of undeclared type 'valueMirror' when using Mirror - swift

I am trying to map a struct to other class that have same properties. but it keep showing this error
Use of undeclared type 'valueMirror'
My code
extension Mapper {
func map<T:Object>(to type: T.Type){
let object = T()
let m = Mirror(reflecting: self)
for property in m.children {
guard let key = property.label else { continue }
let value = property.value
let valueMirror = Mirror(reflecting: value)
if valueMirror.displayStyle == .collection {
let array = value as! valueMirror.subjectType // <-- error
object.setValue(array.asRealMList, forKey: key)
} else {
object.setValue(value, forKey: key)
}
}
}
}

valueMirror.subjectType is not a type as far as the compiler is concerned. There must be a compile time type after as!.
Since the only place you are using array is in array.asRealMList, you probably just need to cast value to a type that has the property asRealMList. As you said in the comments, this is an extension on Array.
Luckily Array is covariant, so even without knowing which type of array it is, you'll be able to cast any array to [Any]:
let array = value as! [Any]

valueMirror.subjectType is of type Any.Type.
You probably want to cast value to Any.

Related

How to add another dictionary entry to an existing dictionary to form a new dictionary (i.e. not append)

I want to add another dictionary entry to a dictionary in swift e.g.
let a: [String: Any] = ["Test": 1, "good":false]
let b = a + ["hello": "there"]
print(b)
(Sorry if + looks crazy here, as that's how Kotlin achieves this. I'm more familiar with Kotlin than Swift.)
But I get the error Binary operator '+' cannot be applied to two '[String : Any]' operands
I can't use updateValue too
let a: [String: Any] = ["Test": 1, "good":false]
let b = a.updateValue("hello": "there")
print(b)
It will error stating Cannot use mutating member on immutable value: 'a' is a 'let' constant
I can do it by an extension function as per proposed https://stackoverflow.com/a/26728685/3286489
but it looks overkill.
let b = a.merge(dict: ["hello": "there"])
print(b)
extension Dictionary {
func merge(dict: Dictionary<Key,Value>) -> Dictionary<Key,Value> {
var mutableCopy = self
for (key, value) in dict {
// If both dictionaries have a value for same key, the value of the other dictionary is used.
mutableCopy[key] = value
}
return mutableCopy
}
}
Is there a simple operator I can just add another entry to it to for a new dictionary?
Note: I'm not referring to append as per How to append elements into a dictionary in Swift?, as I receive an immutable dictionary let that I need to add another entry to it.
There is a built-in merging(_:uniquingKeysWith:) function on Dictionary that does exactly what you need.
let dictionary = [1:1]
let otherDictionary = [1:2, 2:3]
// This will take the values from `otherDictionary` if the same key exists in both
// You can use `$0` if you want to take the value from `dictionary` instead
let mergedDict = dictionary.merging(otherDictionary, uniquingKeysWith: { $1 })
If you want, you can easily define a + operator for Dictionary that uses the above function.
extension Dictionary {
static func + (lhs: Self, rhs: Self) -> Self {
lhs.merging(rhs, uniquingKeysWith: { $1 })
}
}
let addedDict = dictionary + otherDictionary

Check if variable is computed or stored

In my app I translate objects from custom classes into dictionaries so that they can be saved locally in a plist as well as on a server. I use the following to turn the properties of a class into a dictionary:
func dictionary() -> [String : Any] {
var count: UInt32 = 0;
let myClass: AnyClass = self.classForCoder;
let properties = class_copyPropertyList(myClass, &count);
var dictionaryRepresentation: [String:Any] = [:]
for i in 0..<count {
let property = properties![Int(i)]
let cStringKey = property_getName(property);
let key = String(cString: cStringKey!)
dictionaryRepresentation[key] = self.value(forKey: key) as Any
}
return dictionaryRepresentation
}
I have a problem, however, with computed properties. It seems that those are computed and the returned value gets put into the dictionary as well, which I would like to avoid. So here is my question:
Is it possible to check whether is a property computed programatically using only its name?
I am assuming this could be possible by trying to assign a value to it which would give me an error or some similar approach.
Here is what seems to be a working solution, based on suggestion by dasblinkenlight.
Rather than using the Objective-C method outlined above, create a Mirror of the class which has a children made up of all settable properties, therefore excluding computables.
Used like this:
let mirror = Mirror(reflecting: MyObject)
for case let (label?, value) in mirror.children {
print (label, value)
}
Here label is the name of the variable and value is obviously the value.
EDIT: In case anyone wants to convert objects into dictionary, I am posting the full code here as well. Do however remember that if values are custom objects as well, those will need to be converted too.
func dictionary() -> [String:Any] {
let mirror = Mirror(reflecting: self)
var dictionaryRepresentation = [String:Any]()
for case let (label, value) in mirror.children {
guard let key = label else { continue }
dictionaryRepresentation[key] = value
}
return dictionaryRepresentation
}
You can try property_copyAttributeList(_:_:) function, it may contain a read-only marker for swift's computed properties. Although I guess let properties also will have that marker, so you must find a way to differ them.

Swift Dictionary access value through subscript throws Error

Accessing a Swift Dictionary value through subscript syntax is gives error Ambiguous reference to member 'subscript'
Here is the code
class Model {
struct Keys {
static let type :String = "type" //RowType
static let details :String = "details"
}
var type :RowType = .None
var details :[Detail] = []
init(with dictionary:Dictionary<String, Any>) {
if let type = dictionary[Keys.type] as? String {
self.type = self.rowTypeFromString(type: type)
}
if let detailsObj = dictionary[Keys.details] as? Array { //Error : Ambiguous reference to member 'subscript'
}
}
}
if i remove the type casting as? Array at the end of optional-binding it compiles fine
I am expecting the value of details key to be an Array, I know that i can use [String,Any] instead of Dictionary<Key, Value>, What is causing the issue ?
Array doesn't work like NSArray, you explicitly need to tell what type your array is storing.
If you want to store Detail objects in it, the proper syntax is Array<Detail> or simply [Detail]
if let detailsObj = dictionary[Keys.details] as? Array<Detail> {
}
Issue is solved by explicitly specifying the Type of objects the array contains, In my case it was Array<[String:Any]>
if let detailsObj = dictionary[Keys.details] as? Array<[String:Any]> { //we should also specify what type is present inside Array
}
Credits: #Hamish, #Dávid Pásztor
Thanks!

How to check if a variable is nil

I have a variable
var a: [AnyObject? -> Void]
and I am adding data in to it by append method. Now I want to check if the variable is nil or not. I tried using [] but not working and also tried "", this also not working, can anyone tell what is the meaning of this variable and how to check if it is nil.
As far as I understand, var a is an Array of functions that take an optional Object of any type, and return void. So these functions's parameter IS optional, but the Array itself isn't : it cannot be nil, or it would be declared [AnyObject? -> Void]? , no?
EDIT : if, nevertheless, you declared this a as an optional (but WHY would you do that ?) - adding a ? - you check an optional existence with if let :
if let b = a {
// a not nil, do some stuff
} else {
// a is null
}
If you just want to check if the array is empty, use isEmpty method from Swift Array
Update: Xcode 7.3 Swift 2.2
If you want to check if a variable is nil you should use if let to unwrap if for you. There is no need to create a second var.
let str = "123"
var a = Int(str)
if let a = a {
print(a)
}
Or
if let a = Int(str) {
print(a)
}
In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.
So, You can check it with below code:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber != nil {
println("convertedNumber contains some integer value.")
}
// prints "convertedNumber contains some integer value."
Please refer this about nil for more information.
In Swift 3.0
if let imageURL = dictObj["list_image"] as? String {
print(imageURL)
}
You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value.
var a:Int=0
if let b=a{
println(a)
} else {
println("Value - nil")
}
But for Strings you can also use .isEmpty() If you have initialized it to "".
var str:String=""
if !str.isEmpty(){
println(str)
}
For me none of the above solutions worked when I was using an AVFoundation object.
I would get Type 'AVCaptureDeviceInput does not conform to protocol 'BooleanType' when I tried if (audioDeviceInput) and I would get Binary operator '!=' cannot be applied to operands of type 'AVCaptureDeviceInput' and 'nil'.
Solution in my situation
if (audioDeviceInput.isEqual(nil))
nil is a pointer like any other and can be referenced as such, which is why this works.

How to add nil value to Swift Dictionary?

I have made a request to my server in my app. And posted data something like this.Server side is waiting for all parameters even they are nil. But i couldn't add nil values to dictionary.
var postDict = Dictionary<String,AnyObject>
postDict[pass]=123
postDict[name]="ali"
postDict[surname]=nil // dictionary still has only pass and name variables.
Is there a way to add nil value to dictionary ?
How to add nil value to Swift Dictionary?
Basically the same way you add any other value to a dictionary. You first need a dictionary which has a value type that can hold your value. The type AnyObject cannot have a value nil. So a dictionary of type [String : AnyObject] cannot have a value nil.
If you had a dictionary with a value type that was an optional type, like [String : AnyObject?], then it can hold nil values. For example,
let x : [String : AnyObject?] = ["foo" : nil]
If you want to use the subscript syntax to assign an element, it is a little tricky. Note that a subscript of type [K:V] has type V?. The optional is for, when you get it out, indicating whether there is an entry for that key or not, and if so, the value; and when you put it in, it allows you to either set a value or remove the entry (by assigning nil).
That means for our dictionary of type [String : AnyObject?], the subscript has type AnyObject??. Again, when you put a value into the subscript, the "outer" optional allows you to set a value or remove the entry. If we simply wrote
x["foo"] = nil
the compiler infers that to be nil of type AnyObject??, the outer optional, which would mean remove the entry for key "foo".
In order to set the value for key "foo" to the AnyObject? value nil, we need to pass in a non-nil outer optional, containing an inner optional (of type AnyObject?) of value nil. In order to do this, we can do
let v : AnyObject? = nil
x["foo"] = v
or
x["foo"] = nil as AnyObject?
Anything that indicates that we have a nil of AnyObject?, and not AnyObject??.
You can use the updateValue method:
postDict.updateValue(nil, forKey: surname)
As documented in here, setting nil for a key in dictionary means removing the element itself.
If you want null when converting to JSON for example, you can use NSNull()
var postDict = Dictionary<String,AnyObject>()
postDict["pass"]=123
postDict["name"]="ali"
postDict["surname"]=NSNull()
let jsonData = NSJSONSerialization.dataWithJSONObject(postDict, options: NSJSONWritingOptions.allZeros, error: nil)!
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)!
// -> {"pass":123,"surname":null,"name":"ali"}
postDict[surname] = Optional<AnyObject>(nil)
You can use the Optional type
var postDict = ["pass": 123, "name": "ali", "surname": Optional()]
Below dictionary will hold one key with nil value
var dict = [String:Any?]()
dict["someKey"] = nil as Any?
To add a nil value to a dictionary in Swift, your dictionary's values must be of the Optional type.
Consider a Person class:
class Person {
let name: String
weak var spouse: Person?
init(name: String, spouse: Person?) {
self.name = name
self.spouse = spouse
}
}
Instances of the Person type can have a name and an optional spouse. Create two instances, and add the first to a dictionary:
let p1 = Person(name: "John", spouse: nil)
let p2 = Person(name: "Doe", spouse: p1)
p1.spouse = p2
var people = [p1.name: p1.spouse]
This dictionary (called people) maps names to spouses, and is of type [String: Person?]. You now have a dictionary with a value of Optional type: Person?.
To update the value of the key p1.name to be nil, use the updateValue(_: forKey:) method on the Dictionary type.
people.updateValue(nil, forKey: p1.name)
people[p1.name]
The value for the key p1.name is now nil. Using updateValue(_: forKey:) is a bit more straightforward in this case because it doesn't involve making a throwaway instance, setting it to nil, and assigning that instance to a key in a dictionary.
NB: See rintaro's answer for inserting null into a post's dictionary.
var dict = [Int:Int?]()
dict[0] = (Int?).none // <--- sets to value nil
dict[0] = nil // <-- removes
dict[0] = .none // <-- same as previous, but more expressive
switch dict[0] {
case .none:
Swift.print("Value does not exist")
case .some(let value):
if let value = value {
Swift.print("Value exists and is", value)
} else {
Swift.print("Value exists and is nil")
}
}
postDict[surname]=nil
When you use subscript to set nil. It deletes the key if exists. In this case key surname will be removed from dictionary if exists.
To set value as nil, there are certain ways.
postDict.updateValue(nil, forKey: surname)
or
let anyObjectNil : AnyObject? = nil
postDict[surname] = anyObjectNil
or
postDict[surname] = nil as AnyObject?