Code snippets:
This is from a struct called Static:
static var messages: Dictionary = [:]
This is inside a class function:
if Static.messages[sender] == nil{ //no message history, create array then append
var messages: [NSMutableDictionary] = [message]
Static.messages[sender] = messages
}
else{ //there is message history, so append
(Static.messages[sender] as Array).append(message)
}
Error:
Immutable value of type 'Array<T>' only has mutating members named 'append'
I'm trying to make a Dictionary of conversations with each item being a person. Each array will be a list of messages. The messages are of type dictionary. Any idea why I'm getting this message?
If you're clear with the compiler about what your dictionary contains, you won't need the cast that is making this difficult. From what you've posted, the actual type of Static.messages will need to be something like Dictionary<NSObject, Array<NSMutableDictionary>>.
Your current attempt casts a dictionary value as an Array and then tries to append -- this fails because Swift treats the result of this kind of cast as immutable. What you need to do instead is to simply use optional chaining:
// instead of:
(Static.messages[sender] as Array).append(message)
// use:
Static.messages[sender]?.append(message)
Related
I have a variable:
reas : [String:[User]]?
I want to sort it and put it in another view controller variable
vc.OrederReas = reas.sorted { $0.1.count > $1.1.count }
I'm getting an error that orderReas needs to be of type
[Dictionary<String, [User]>.Element]()
Which I made, Now I want to put a signal element from orderReas (which should be String:[User], and maybe sometimes all the elements, but this is not the issue).
but I don't know how to define it, I'm getting errors such as:
Cannot assign value of type 'Dictionary<String, [User]>.Element' (aka '(key: String, value: Array<User>)') to type '[Dictionary<String, [User]>.Element]' (aka 'Array<(key: String, value: Array<User>)>')
But I can't define a variable as
var OrederReas = Dictionary<String, [User]>.Element
To sum up I want a variable which holds [String:[User]], sort him into another variable, and Another variable which will hold one either one element or all the elements from the original variable.
Thank you!
When you are sorting a Dictionary the result will be a array Tuple of Key and Value.
in your case, if you want to have dictionaries of the same type you can convert your Result(Tuple) to a Dictionary so you can do this:
let tupleOrederReas = reas.sorted { $0.value.count > $1.value.count }
let dictionaryOrederReas = tupleOrederReas.reduce(into: [:]) { $0[$1.key] = $1.value }
//Finally Pass the Dictionary to VC variable
vc.OrederReas = dictionaryOrederReas
I am trying to append value to dictionary which I have declared like this.
var setHomIconDict:[(iconImg: UIImage, Operator: String, oprCode: String, oprMerchCode:String)]!
I am not sure its dictionary though. I am learning swift and I found a Intresting code on net. Anyway I am confused on how will I append values to this. I tried
setHomIconDict.append((iconImg:img!, Operator: "Strin", oprCode: "Hello", oprMerchCode: "Huja"))
But i get this error : fatal error: unexpectedly found nil while unwrapping an Optional value . here is the image
Can anyone suggest an appropriate way.
setHomIconDict is not Dictionary it is an Array of tuple and you are getting this crash because you haven't initialized the setHomIconDict object, you have just declared its type. So initialized it with its declaration.
var setHomIconDict:[(iconImg: UIImage, Operator: String, oprCode: String, oprMerchCode:String)] = []
Note: Instead of creating array of tuple better solution is to create one custom model Class with the property that you want to set/access, then create array of that custom Class objects and use it.
You are probably better off creating a struct to hold your values. Then your array would be an array of that struct.
struct homIcon {
var iconImg: UIImage
var Operator: String
var oprCode: String
var oprMerchCode:String
}
var setHomIconArray:[homIcon] = []
let newHomIcon = homIcon(iconImg: img!, Operator: "Strin", oprCode: "Hello", oprMerchCode: "Huja")
setHomIconArray.append(newHomIcon)
As Nirav says, the syntax you are using creates an array of tuples. If you want a dictionary get rid of the parentheses.
You want to define key/value pairs using this syntax:
var aDict = [key:value, key:value, key:value]
Then you can add new key/value pairs using:
aDict[newKey] = newValue
Is your goal to create and use a dictionary, or is it your goal to user and understand the structure that you found on the net?
I am creating at launch Dictionaries with var because I will modify them later when user does something. Dictionaries are added inside an Array in a singleton class to be used in multiple places but I get the warning "Variable 'variableName' was never mutated, consider...."
in the place I am creating them
If I make them with let and when I get object form array to modify it if I take it from array with var, no crash, no warning, no nothing...
What is the explanation for this?
UPDATE:
My Singleton Class:
class Config {
static let sharedInstance = Config()
var array_shapes: Array<Dictionary<NSObject,AnyObject>> = Array()
func createInitialShapeArray(){
var avion = createShapeDictionaryFor("Avion", objectName: "Avion", badgeStatus: "0", shapeImageName: "shape_avion");
//.......more objects like avion
array_shapes = [avion,//.....the other objects];
}
func createShapeDictionaryFor(objectID:String, objectName:String, badgeStatus:String, shapeImageName:String) -> Dictionary<NSObject,AnyObject>{
var dict: Dictionary<NSObject,AnyObject> = [:]
dict["objectID"] = objectID
dict["objectName"] = objectName
dict["badgeStatus"] = badgeStatus
dict["shapeImageName"] = shapeImageName
return dict;
}
}
And when I am mutating dictionaries (In main class):
#IBAction func btnPressed_done(sender:UIButton){
pennyPincherGestureRecognizer.recognize();
screenShotMethod()
var dict = Config.sharedInstance.array_shapes[Config.sharedInstance.currentShapeIndex] as Dictionary<NSObject,AnyObject>
dict["badgeStatus"] = "1"
self.initNextShape()
}
var avion has the warning "Variable 'variableName' was never mutated, consider...."
It is not an error trough, it's a warning and I was curious if I could silence them or what can I do to make them dissappear
Facts
You are declaring avion as a local variable of the method createInitialShapeArray
You are not mutating avion in the scope where it is defined
avion is a Dictionary therefore a Struct (value type rules are applied)
Conclusion
There is no need to declare avion as a variable, it should be a constant.
Please note that where you write
array_shapes = [avion, ...]
you are creating a copy of avion (because it's a Dictionary).
So if you change the value inside array_shapes you are changing another value.
Therefore, at the end of the day, you are not mutating avion... and the compiler is right, it should be a constant.
Example
Please consider the following code
func foo() {
var dict = [1: "One"] // <-- Compiler warning
var anotherDict = dict
anotherDict[2] = "Two"
}
Here I am getting the same compiler warning
Variable 'dict' was never mutated; consider changing to 'let' constant
This happens because I am changing anotherDict that is not just another reference to the same value, it is actually a totally different value. This is the rule with Struct(s) and Enum(s) because they are Value Types.
Hope this helps.
In Swift arrays and dictionaries are declared as struct so when you pass them to other function or use them in assignments their value is copied and not passed as reference the same way it's done for classes, this means that when you pass avion to the append() function of your array you pass a copy of the dictionary so the original variable is never mutated.
The same things happens when you try to modify on dictionary in the array thus copying the dictionary of your interest in dict: you aren't modifying the array inside your shared instance but the local variable dict.
I am busy converting to Swift and am trying to figure out how to do the following in Swift
NSArray arrayOfStrings1 = {#"Substring1", #"Substring2", nil};
Dictionary dict = {#"MainString1", arrayOfStrings1};
So in Swift I have the following:
var dictionary = [String: Array<String>]() // is this correct ??
var array: [String] = ["Substring1", "Substring2"]
dictionary["MainString1"] = ["Substring1.1", "Substring1.2"]
dictionary["MainString2"] = ["Substring2.1", "Substring2.2"]
Now in order to access the array I use
let array = dictionary["MainString1"]
let item0 = array[0]
but this fails with a compiler error which seems to indicate that array is in fact a String not an array of strings.
What am I missing here?
The issue is actually that a subscript lookup for a Dictionary in Swift returns an optional value:
This is a pretty great feature - you can't be guaranteed that the key you're looking for necessarily corresponds to a value. So Swift makes sure you know that you might not get a value from your lookup.
This differs a little bit from subscript behavior for an Array, which will always return a value. This is a semantically-driven decision - it's common in languages for dictionary lookups to return null if there is no key - but if you try to access an array index that does not exist (because it's out of bounds), an exception will be thrown. This is how Swift guarantees you'll get a value back from an array subscript: Either you'll get one, or you'll have to catch an exception. Dictionaries are a little more lenient - they're "used to" not having the value you're asking for.
As a result, you can use optional binding to only use the item if it actually has a value, like so:
if let theArray = dictionary["MainString1"] {
let item0 = theArray[0]
} else {
NSLog("There was no value for key 'MainString1'")
}
I am having a devil of a time trying to work with Dictionaries in Swift. I have created the following Dictionary of Dictionaries but I am unable to unpack it.
var holeDictionary = Dictionary<String,Dictionary<String,Dictionary<String,Int>>>()
I can get the first Dictionary out with:
var aDictionary = holeDictionary["1"]
But trying to access the next Dictionary within it gives me an error as follows:
var bDictionary = aDictionary["key"] // [String : Dictionary<String, Int>]?' does not have a member named 'subscript'
I know what the contents of the Dictionaries are and can verify them with a println(aDictionary). So how can I get to the Dictionaries buried deeper down?
The key subscript on Dictionary returns an optional, because the key-value pair may or may not exist in the dictionary.
You need to use an if-let binding or force unwrap the optional before you can access it to subscript it further:
if let aDictionary = holeDictionary["1"] {
let bDictionary = aDictionary["key"]
}
Edit, to add forced unwrap example:
If you're sure that the key "1" exists, and you're okay with assert()ing at runtime if the key doesn't exist, you can force-unwrap the optional like this:
let bDictionary = holeDictionary["1"]!["key"]
And if you're sure that the key "key" will exist, you'd do this instead:
let bDictionary = holeDictionary["1"]!["key"]!
Accordingly to the swift documentation:
Because it is possible to request a key for which no value exists,
a dictionary’s subscript returns an optional value of the dictionary’s
value type
When you retrieve an item from a dictionary you have an optional value returned. The correct way to handle your case is:
var holeDictionary = Dictionary<String,Dictionary<String,Dictionary<String,Int>>>()
if let aDictionary = holeDictionary["1"] {
var bDictionary = aDictionary["key"]
}