i have dictionary array in witch i have to modify the array object isRead
let dict = arr[indexPath]
var Added = dict["IsRead"] as! NSNumber
if Added == 0
{
Added = 1
}
Why NSNumber? The name isRead implies that the type is Bool.
Due to value semantics you have to modify arr
let dict = arr[indexPath.row]
if let isRead = dict["IsRead"] as? Bool, isRead == false {
arr[indexPath.row]["IsRead"] = true
}
Related
I have an array of Dictionaries, like so
var myArray: [Dictionary<String, Any>] = [Dictionary<String, Any>]()
Somewhere in my class i add values there, like so:
var myDict = Dictionary<String, Any>()
myDict["Id"] = "someUniqueId"
myDict["v1"] = -42
self.myArray.append(myDict)
Then later i try to update the v1 inside this dict like so:
self.myArray.first(where: { $0["Id"] == "someUniqueId" })?["v1"] = -56
However, the compiler tells me:
Cannot assign through subscript: function call returns immutable value
Any way i can modify the value in array outside of copying the whole dictionary, removing it from array, and re-inserting?
UPDATE This dictionary is not strongly typed because what is inside the dictionary, both types and fieldnames, are controlled by the user in an external system. E.g. we download some metadata and then render controls for this dynamic data.
This is because Swift Dictionary is a value type.
Use a custom class or you can use NSMutableDictionary for this purpose (because NSDictionary is immutable).
var myArray = [NSMutableDictionary]()
var myDict = NSMutableDictionary()
myDict["Id"] = "someUniqueId"
myDict["v1"] = -42
myArray.append(myDict)
myArray.first(where: { $0["Id"] as? String == "someUniqueId" })?["v1"] = -56
print(myArray)
// [{
// Id = someUniqueId;
// v1 = "-56";
// }]
You can make it easier for yourself by wrapping your dictionary in a simple class
class Config {
private var dict: [String: Any]
init(_ dict: [String: Any]) {
self.dict = dict
}
func valueFor(_ key: String) -> Any? {
return dict[key]
}
func setValue(_ value: Any, forKey key: String) {
dict[key] = value
}
}
and use that in your array
var myArray = [Config]()
And use it like this
array.filter { $0.valueFor("Id") as? String == "someUniqueId" }
.first?.setValue(-56, forKey: "v1")
That way you can avoid using classes like NSMutableDictionary and keeping it more pure Swift. Another advantage with a custom class is that you can add functionality to it to simplify your code using it, so for instance if you will be looking up dictionaries by "Id" a lot we can add a computed property for it
var id: String? {
return valueFor("Id") as? String
}
and then the example above would become
array.filter { $0.id == "someUniqueId" }.first?.setValue(-56, forKey: "v1")
if (userFollowingArray[indexPath.row]["watcher_following"] as! Bool) == false {
let dict : NSMutableDictionary = userFollowingArray[indexPath.row] as! NSMutableDictionary
print(dict)
dict["watcher_following"] = 1
self.userFollowingArray[indexPath.row] = dict as! Dictionary<String, Any>
}
I want to update watcher_following key with true/false but it throws an exception.
[_TtGCs26_SwiftDeferredNSDictionarySSP__
_swift_setObject:forKeyedSubscript:]: unrecognized selector sent to instance
Do not use NSMutable... collection types in Swift
Declare userFollowingArray as Swift Array
var userFollowingArray = [[String:Any]]()
Get the Dictionary as variable
var dict = userFollowingArray[indexPath.row]
Check the value
if dict["watcher_following"] as! Bool == false {
Update it if necessary and assign the dictionary back to the array.
dict["watcher_following"] = true
userFollowingArray[indexPath.row] = dict
}
The last step is necessary due to value semantics
It's much more convenient to use a custom struct or class rather than a dicionary.
Declare var for mutable types, let is only for immutable/constant types. not needed to use objective c NSMutableDictionary type.
if dict["watcher_following"] as! Bool == false {
var dict : Dictionary<String, Any> = userFollowingArray[indexPath.row] as! Dictionary<String, Any>
dict["watcher_following"] = 1
self.userFollowingArray[indexPath.row] = dict as! Dictionary<String, Any>
}
Second object of quickFilterDictionary in self.preferencesListFilterDictionary is nil. How to add [NSIndexPath] index path (as key) and NSNumber (as value) in Dictionary?
Note: first object is added successfully, only the 2nd object is nil when I printed self.preferencesListFilterDictionary in console. May I know , what am I doing wrong in below code?
self.preferencesListFilterDictionary["price"] = 1000
self.quickFilterArr = [localizedStrOf("deliveryNowOnly"),localizedStrOf("rated")]
var quickFilterDictionary = Dictionary<NSIndexPath, NSNumber?>()
for obj in self.quickFilterArr {
let row = self.quickFilterArr.indexOf(obj)
let indexPath = NSIndexPath(forRow:row!, inSection: 0)
quickFilterDictionary[indexPath] = NSNumber(bool: false)
}
print(quickFilterArr.count)
print(quickFilterDictionary)
self.preferencesListFilterDictionary.updateValue(quickFilterDictionary as? AnyObject, forKey: "quickFilterDictionaryKey")
print(self.preferencesListFilterDictionary)
console print:
▿ [1] : 2 elements
- .0 : "quickFilterDictionaryKey"
- .1 : nil
To get above dictionary bool from number, I wrote following code -
func getQuickFilterValueOfIndexpath(indexPath:NSIndexPath) -> Bool {
if let val = self.preferencesListFilterDictionary["quickFilterDictionaryKey"] {
// now val is not nil and the Optional has been unwrapped, so use it
let tempDict = val as! Dictionary<NSIndexPath, NSNumber?>
if let boolVal = tempDict[indexPath] {
return boolVal!
}
}
return false
}
I think you are confused on the difference between a Row, an IndexPath, and an Index.
In the following code:
let row = self.quickFilterArr.indexOf(obj)
If you option click on row, you will see that it is an object of type Array.Index?. It is not an row.
Also is there a reason you are using NSNumber, NSIndexPath and update value for key? As opposed to Number, IndexPath and just updating your dictionary values with:
preferencesListFilterDictionary["quickFilterDictionaryKey] = quickFilterDictionary
If you option click on quickFilterArr and it is an array of IndexPaths [IndexPath] - To reference the IndexPath at your chosen index in that array you would just do:
if let arrayIndex = quickFilterArr.indexOf(obj) {
//if your array is an array of Index Paths
//you would then pull the IndexPath object at the index you have defined above
let indexPath = quickFilterArr[arrayIndex]
quickFilterDictionary[indexPath] = Number(bool: false)
}
I am on point where I gotta compare non optional value with nil. But I can't do it because Xcode says:
Comparing non-optional value of type 'Int' to nil always returns false
So I created Struct and then made variable: var products: [Product] = []
How I am able to compare it with nil?:
if products[indexPath.row].snusPortions == nil
{
cell.snusPortionsAmountLabel.text = "N/A"
}else
{
cell.snusPortionsAmountLabel.text = String(products[indexPath.row].snusPortions)
}
I've assigned values to them like this:
let ref = FIRDatabase.database().reference().child("Snuses").queryOrdered(byChild: "Brand").queryEqual(toValue: brandName)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
let enumerator = snapshot.children
while let thisProduct = enumerator.nextObject() as? FIRDataSnapshot
{
print(thisProduct.value) // So I may see what the data is like and know how to extract it
// Chances are you'd have to create a dictionary
let thisProductDict = thisProduct.value as! [String:AnyObject]
let productName = thisProductDict["Products"] as! String
let snusPortions = thisProductDict["PortionsCan"] as? Int
let productObject = Product(snusProductTitle: productName, snusNicotine: snusNicotine, snusPortions: snusPortions!, snusFlavor: snusFlavor, snusWeight: snusWeight!, snusShippingWeight: snusShippingWeight, snusProductImageURL: productURL)
self.products.append(productObject)
print(self.products)
}
self.tableView.reloadData()
}
})
This is Product struct:
struct Product {
var snusProductTitle: String
init()
{
snusProductTitle = ""
}
init(snusProductTitle: String){
self.snusProductTitle = snusProductTitle
}
}
While testing it says snusPortions is nil but I said to make it "N/A" if it is nil, why?
It sounds like you are confusing yourself between the local variable snusPortions and the Product property snusPortions.
In your Product definition, the property snusPortions is an Int. It can never be nil. Hence, in this code:
if products[indexPath.row].snusPortions == nil
... this Product's snusPortions will never be nil, and we will never set the text to "N/A".
Now let's look at your other code:
let snusPortions = thisProductDict["PortionsCan"] as? Int
This is a completely different snusPortions. It can be nil, namely, if thisProductDict lacks a "PortionsCan" key or if its value is not castable to Int.
I would like to make an Optional Dictionary Variable inside of a Class so that when I create an instance I don't HAVE to add that argument...
example
class Stuff {
var dictionary: [String: Double]?
init(dictionary: [String:Double]?=["":0]){
}
}
var instance1 = Stuff(dictionary:["length":1.5])
var array: [Stuff] = [instance1, instance2]
let arraySet = (array[indexPath.row])
let X = arraySet.dictionary!
cell.Label.text = "\(X)"
This works but when i assign it to a cell.label.text the output shows Brackets...
"[length:1.5]"
How can i get rid of the brackets???
It's quite complicated to get rid of the brackets, because the key/value pair must be extracted out of the dictionary:
class Stuff {
var dictionary: [String: Double]?
init(dictionary: [String:Double]?=["":0.0]){
self.dictionary = dictionary
}
}
let instance = Stuff(dictionary:["length":1.5])
if let dict = instance.dictionary where dict.count > 0 {
let key = dict.keys.first!
let value = dict[key]!
label.text = "\(key) : \(value)"
}
If you create the dictionary with non-optional literals, consider to declare the variable dictionary as non-optional