How to update key of dictionary in Swift 3 - swift

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>
}

Related

Confusion with downcasting value in Swift

I have two arrays.
var searchedArray: NSMutableArray!
var libraryArray: NSMutableArray!
I'm trying to fix my searchBar functionality because it always shows nil(searchedArray = nil).
I've tried to downcast it in different ways but it doesn't work.
Here's the snippet.
let laMutableCopy = (downloadManager.libraryArray as NSArray).mutableCopy()
searchedArray = laMutableCopy.filter{
guard let dict = $0 as? Dictionary<String, Any> else {return false}
guard let title = dict["title"] as? String else {return false}
return title.range(of: searchText, options: [caseInsensitive, .anchored]) != nil
} as? NSMutableArray
Here's an example that would work:
var libraryArray = [
["title": "foo"],
["title": "bar"]
]
var filteredArray = libraryArray.filter{
// your production code doesn't have to be like this, but when attempting to debug
// its very helpful to break each cast out into its own assign to see where you
// are failing
guard let dict = $0 as? Dictionary<String, Any> else { return false }
guard let title = dict["title"] as? String else { return false }
return title.range(of: "fo", options: [.caseInsensitive, .anchored]) != nil
} as? Array<Dictionary<String, Any>>
The problem with your code is that you're casting the result of the filter (a swift Array) to an NSMutableArray. Swift arrays can be cast to NSArray, but they cannot be cast to NSMutableArray without constructing a copy like so:
(libraryArray as NSArray).mutableCopy()

Swift update value inside Dictionary<String, Any> in an Array

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")

is any function to modify the json parse dictionary array

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
}

How do I convert NSDictionary to Dictionary?

I have already updated to XCode 8 and now I need to convert my code from Swift 2 to Swift 3.
Before, when I want to convert NSDictionary to Dictionary, I just wrote the following:
let post_paramsValue = post_params as? Dictionary<String,AnyObject?>
where post_params is NSDictionary.
But now with Swift 3, I am receiving this error:
NSDictionary is not convertible to Dictionary
Why? What's changed?
Edit 1
I've also tried the following:
let post_paramsValue = post_params as Dictionary<String,Any>
But that gives this error:
Edit 2
I've also tried the following:
let post_paramsValue = post_params as Dictionary<String,Any>
Where I declare NSDictionary instead of NSDictionary!, but it doesn't work; I got this error:
Edit 3
I've also tried the following:
let post_paramsValue = post_params as Dictionary<String,Any>!
But I received this error:
NSDictionary in Objective-C has always non-optional values.
AnyObject has become Any in Swift 3.
Considering the first two "rules" NSDictionary can be bridge cast to Dictionary
let post_paramsValue = post_params as Dictionary<String,Any>
If the source NSDictionary is an optional you might use as Dictionary<String,Any>? or as? Dictionary<String,Any> or as! Dictionary<String,Any> or as Dictionary<String,Any>! depending on the actual type of the NSDictionary
For those who have a problem with NSDictionary, simply use this extension:
Swift 3.0
extension NSDictionary {
var swiftDictionary: Dictionary<String, Any> {
var swiftDictionary = Dictionary<String, Any>()
for key : Any in self.allKeys {
let stringKey = key as! String
if let keyValue = self.value(forKey: stringKey){
swiftDictionary[stringKey] = keyValue
}
}
return swiftDictionary
}
}
You just need to declare the NSDictionary properly in objc
For example: NSDictionary<NSString *, NSString*> gets translated automatically to [String: String] in swift interfaces

Swift: Variable of Optional Dictionary inside Class: Shows Brackets in Output

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