Swift add object in to AnyObject - ios

I need add an object into AnyObject
let swiftArray: [String: AnyObject] = ["one": "asd", "two": "asd", "three": "asd"]
How to add more objects?
Like,
let swiftArray: [String: AnyObject] = ["one": "asd", "two": "asd", "three": "asd"]
print(swiftArray)
swiftArray.append("test": "test") // NOT WORKING

Swift syntax is rather confusing. You are actually trying to create a Dictionary instead.
To use an Array:
var swiftArray: [String] = ["one", "two", "three"]
swiftArray.append("test")
--> Notice that you must use var instead of let for the Array to be mutable.
To use a Dictionary:
var swiftDict: [String: String] = ["one": "value"]
swiftDict["newElement"] = "newValue"
Please throughly read the Swift 2.1 documentation here.

You should probably read up on how swift works!!!
I'm gonna hold your hand on this one, and show you all the things that are off here.
FIRST, you're declaring your variable with a let statement, which creates Immutable variables (i.e., they can't change!). If you'd like to create a variable that can change, user var ..., so
var swiftDict: [String: AnyObject] = ["one": "asd", "two": "asd", "three": "asd"]
SECOND, what you're thinking of here is a dictionary, not an array. Arrays can be thought of as lists, or stacks of data, where each piece of data has a number, and is stacked on the last piece of data. A dictionary is more like a pool of data, where each piece has a name, or key, you call to retrieve it.
Rule of thumb, if you're got values tied together, you've got a dictionary.
THIRD, it's really easy to add to a dict, just use the following syntax.
swiftDict["four"] = "asd"
If you're still confused, try google, and feel free to ask for more info.

Related

Dictionary [String: String] keys order changed when converted to array swift

I have a dictionary like below,
var dataSource: [String: String] = ["FirstName": "Austin",
"ListName": "Michael",
"Address": "Street Address",
"City": "Chennai"]
I want to populate these values in a UITableView, so I tried to get all the keys from Dictionary to an Array like below,
let dataArray = Array(dataSource.keys)
I got the output as [String] like,
["LastName", "FirstName", "City", "Address"]
The problem is, the order of the keys has changed, I want the array in the same order as dictionary has.
Can you anyone help?
Use plain dictionary as tableview datasource is bad idea.
However Dictionary can not be sorted. So it doesn't matter in what order you add your keys-values to the dictionary.
If you need sorted then use array of dictionary instead.
You should use models instead of plain dictionary that is easy to maintain :]
like
struct User {
var firstName:String?
var lastName:String?
var address:String?
var city:String?
}

How to create the specified data structure in swift ios?

I am trying to create a particular data structure as specified below in Swift.
[{"productId":1,"qty":3},{"productId":2,"qty":1},{"productId":3,"qty":5},{"productId":4,"qty":30},{"productId":5,"qty":13}]
Can some one guide me how to achive it..... I need to add and remove the data structure.
Thanks in advance.....
It is an Array of Dictionaries.
Define it like this :
var dataStructure = [[String: Any]]()
To add something :
var newData = [String: Any]()
newData["productId"] = 1
newData["qty"] = 1
dataStructure.append(newData)
To delete :
dataStructure.remove(at: indexYouWantTodeleteInInt)
It is called as dictionary in swift.
The declaration part can be as follows:
var params: [String:Any]
We can also use like:
var params: [String:Any] = ["user_id" : AppConfiguration.current.user_id]
Now to add key-value pair in it you can do as follows:
params["form_id"] = form_id!
params["parent_category_id"] = id
params["device_token"] = getDeviceToken()
params["app_version"] = APP_VERSION
params["app_device_type"] = originalDeviceType
to remove a key-value pair:
params.removeValue(forKey: "parent_category_id")
to update any value of particular key:
params.updateValue("10", forKey: "form_id")
if the above key is already present it updates the value and if not then it adds a new key to the dictionary
The Above explained part is dictionary. Now you need the data-structure as array of dictionary so you need to declare as
var params: [[String:Any]]
you can perform all the operations you can perform on an array but the value you will get at a particular index will be of type dictionary which I explained above.
Hope this helps you understand what is dictionary and what is array of dictionaries.
In your case you can also write [String: Int] instead of `[String:Any]' but it will restrict you to only have integer values with respect to the keys.
Swift developers usually use Structs in order to create a data structure from a JSON reponse. From Swift 4, JSON parsing has become very easy. Thanks to Codable protocols.
From the above given answer, you can create something like this.
MyStruct.Swift
import Foundation
typealias MyStruct = [[String: Int]]
You can then parse by calling the following method.
let myStruct = try? JSONDecoder().decode(MyStruct.self, from: jsonData)
You can add value by using this.
var newProduct = [String: Any]()
newProduct["productId"] = 941
newProduct["qty"] = 2
myStruct.append(newProduct)
To remove the data
myStruct.remove(at:"Some index")

Unable to retrieve dictionary data from Userdefaults in Swift 3

Do you guys can bring some light on the use of dictionaries with UserDefaults ?
What I want to get is to pass a certain dictionary from a view controller to another one using UserDefaults.
var dict = [String : AnyObject?]()
dict = ["Name": "Henri", "Group": "A", "Category": "4"]
UserDefaults.standard.set.(dict, forKey: "MyDict")
Then I try to retrieve the data
let retrieveDict = UserDefaults.standard.dictionary(forKey:"MyDict")
I got a nice nil answer in the console. When I try with int or float types it is fine... Is there anything I am missing to make this dictionary ?
First of all, your code won't compile.
Second, a dictionary with type [String, AnyObject?] make no sense because you'll be not able to set nil in UserDefaults. You should use empty String maybe for that purpose.
The working code could look like that :
var dict = [String : Any]() // or maybe [String : String] if you sure about value type
dict = ["Name": "Henri", "Group": "A", "Category": "4"]
UserDefaults.standard.set(dict, forKey: "MyDict")
let retrieveDict = UserDefaults.standard.dictionary(forKey:"MyDict")
Hope it helps you :)

Optional Values in NSMutableDictionary

I'm new to Swift, very experienced in Objective-C.
In my app, I am receiving data from a server and mapping it to an NSMutableDictionary. The reason I am using an NSMutableDictionary is that the values are not consistent coming from the server, it's a mix of strings and numbers. And that appears to break a Swift Dictionary that expects only one type of value.
Sometimes the server is not sending a value that the NSMutableDictionary is expecting and it crashes the app.
In my research, it appears that I have to check every object to see if the value exists in Swift before setting it into the NSMutableDictionary.
This is my current code:
let userDictionary:NSMutableDictionary = [
"name": data.objectForKey("name") as! String,
... // many more values
This crashes if there is no "name" value in the response from the server.
It appears the solution would be:
if let nameValue = data.objectForKey("name") as! String {
//not sure what to do in here since the var is assigned as I need
}
// ... check many more values
let userDictionary:NSMutableDictionary = [
"name": nameValue,
// ... assign many more values that I checked above
This seems like a lot of extra code to check every single value from the server. Is there a simpler solution?
Thank you for your time.
#Matt below. Here is the code in detail (took out some of the values in the userDictionary for brevity). I'm taking data from Facebook, adding additional info and saving it to Firebase:
//check all of the values
var birthdayValue:String? = "";
if let value:String? = data.objectForKey("birthday") as? String {
birthdayValue = value;
}
let userDictionary:NSMutableDictionary = [
"name": data.objectForKey("name") as! String,
"birthday": birthdayValue!,
"email": data.objectForKey("email") as! String,
"firstName": data.objectForKey("first_name") as! String,
"lastName": data.objectForKey("last_name") as! String,
"description": "",
"distance": 50,
"facebookID": data.objectForKey("id") as! String,
"location":[ 37.12314, -122.49182 ], //TODO: Get location
"points" : 0,
"rating" : 1,
"school" : "",
]
//we need to convert the FB profile pic to a base 64 string and add it here
let imagePath:String = "https://graph.facebook.com/\(data.objectForKey("id") as! String)/picture?width=375&height=667"
self.getDataFromUrl(NSURL(string: imagePath)!) { (imageData, response, error) -> Void in
//convert the data to base 64
let imgString:String = self.convertDataToBase64(imageData);
let images:Array<String> = [imgString];
userDictionary.setValue(images, forKey: "profilePics")
//save the user to Firebase
userRef.childByAppendingPath(data.objectForKey("id") as! String).setValue(userDictionary)
self.currentUserID = (data.objectForKey("id")) as! String
}
Swift actually support multiple types in a dictionary. The following is legal.
let arr: [NSObject: AnyObject] = [1: "hello", "a": 19, 2: "Swift"]
And you can store optional object in the dictionary:
let arr: [NSObject: AnyObject?] = [1: "hello", "a": 19, 2: nil]
And yes, you might need to check the existence of the value if you do care about it. Instead of if, I would use guard to make sure you can use the variable later.
guard let nameValue = data.objectForKey("name") as? String else {
return
}
// Now you can safely use nameValue.
In my app, I am receiving data from a server and mapping it to an NSMutableDictionary
There is no need for this at all. The data is coming to you as a dictionary (at least I presume it is; if it weren't, you could hardly be calling objectForKey, it seems to me). So now just proceed to use it. There is nothing to "map".
For example, suppose that data is the result of calling NSJSONSerialization's JSONObjectWithData:options: on an original NSData d. And suppose what you expect this to serialize to is a dictionary. So after you've said
var data = try! NSJSONSerialization.JSONObjectWithData(
d, options:[]) as! [NSObject:AnyObject]
...you are finished: that's a mutable dictionary and you are off to the races.
If your data is a mix of strings and numbers you could perhaps try to store it as AnyObject in the dictionary, e.g. [String: AnyObject]
Then you could just try to save your data like this:
var userDictionary: [String: AnyObject] = [:]
userDictionary["name"] = data.objectForKey("name")
And when you need to access it:
if let name = userDictionary["name"] as? String {
// Do something with name
}
If you don't want to save it as AnyObject I'd suggest you create a struct instead.
as! is a force downcast, which causes an exception if this downcast isn't possible (which obviously is the case if the value is nil). as?, on the other hand, only downcasts where possible, and results in nil otherwise (which sounds like what you want).
let userDictionary:NSMutableDictionary = [
"name": data.objectForKey("name") as? String,
... // many more values
]
This should work.
Edit: Never mind, this would only work if you'd use a native Swift dictionary. It's still useful to know about the difference between as? and as!, though.

Ordered map in Swift

Is there any built-in way to create an ordered map in Swift 2? Arrays [T] are sorted by the order that objects are appended to it, but dictionaries [K : V] aren't ordered.
For example
var myArray: [String] = []
myArray.append("val1")
myArray.append("val2")
myArray.append("val3")
//will always print "val1, val2, val3"
print(myArray)
var myDictionary: [String : String] = [:]
myDictionary["key1"] = "val1"
myDictionary["key2"] = "val2"
myDictionary["key3"] = "val3"
//Will print "[key1: val1, key3: val3, key2: val2]"
//instead of "[key1: val1, key2: val2, key3: val3]"
print(myDictionary)
Are there any built-in ways to create an ordered key : value map that is ordered in the same way that an array is, or will I have to create my own class?
I would like to avoid creating my own class if at all possible, because whatever is included by Swift would most likely be more efficient.
You can order them by having keys with type Int.
var myDictionary: [Int: [String: String]]?
or
var myDictionary: [Int: (String, String)]?
I recommend the first one since it is a more common format (JSON for example).
Just use an array of tuples instead. Sort by whatever you like. All "built-in".
var array = [(name: String, value: String)]()
// add elements
array.sort() { $0.name < $1.name }
// or
array.sort() { $0.0 < $1.0 }
"If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary provides, see the DictionaryLiteral type for an alternative." - https://developer.apple.com/reference/swift/dictionary
You can use KeyValuePairs,
from documentation:
Use a KeyValuePairs instance when you need an ordered collection of key-value pairs and don’t require the fast key lookup that the Dictionary type provides.
let pairs: KeyValuePairs = ["john": 1,"ben": 2,"bob": 3,"hans": 4]
print(pairs.first!)
//prints (key: "john", value: 1)
if your keys confirm to Comparable, you can create a sorted dictionary from your unsorted dictionary as follows
let sortedDictionary = unsortedDictionary.sorted() { $0.key > $1.key }
As Matt says, dictionaries (and sets) are unordered collections in Swift (and in Objective-C). This is by design.
If you want you can create an array of your dictionary's keys and sort that into any order you want, and then use it to fetch items from your dictionary.
NSDictionary has a method allKeys that gives you all the keys of your dictionary in an array. I seem to remember something similar for Swift Dictionary objects, but I'm not sure. I'm still learning the nuances of Swift.
EDIT:
For Swift Dictionaries it's someDictionary.keys
You can use the official OrderedDictionary from the original Swift Repo
The ordered collections currently contain:
Ordered Dictionary (That you are looking for)
Ordered Set
They said it is going to be merged in the Swift itself soon (in WWDC21)
Swift does not include any built-in ordered dictionary capability, and as far as I know, Swift 2 doesn't either
Then you shall create your own. You can check out these tutorials for help:
http://timekl.com/blog/2014/06/02/learning-swift-ordered-dictionaries/
http://www.raywenderlich.com/82572/swift-generics-tutorial
I know i am l8 to the party but did you look into NSMutableOrderedSet ?
https://developer.apple.com/reference/foundation/nsorderedset
You can use ordered sets as an alternative to arrays when the order of
elements is important and performance in testing whether an object is
contained in the set is a consideration—testing for membership of an
array is slower than testing for membership of a set.
var orderedDictionary = [(key:String, value:String)]()
As others have said, there's no built in support for this type of structure. It's possible they will add an implementation to the standard library at some point, but given it's relatively rare for it to be the best solution in most applications, so I wouldn't hold your breath.
One alternative is the OrderedDictionary project. Since it adheres to BidirectionalCollection you get most of the same APIs you're probably used to using with other Collection Types, and it appears to be (currently) reasonably well maintained.
Here's what I did, pretty straightforward:
let array = [
["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"],
["foo": "bar"]
]
// usage
for item in array {
let key = item.keys.first!
let value = item.values.first!
print(key, value)
}
Keys aren't unique as this isn't a Dictionary but an Array but you can use the array keys.
use Dictionary.enumerated()
example:
let dict = [
"foo": 1,
"bar": 2,
"baz": 3,
"hoge": 4,
"qux": 5
]
for (offset: offset, element: (key: key, value: value)) in dict.enumerated() {
print("\(offset): '\(key)':\(value)")
}
// Prints "0: 'bar':2"
// Prints "1: 'hoge':4"
// Prints "2: 'qux':5"
// Prints "3: 'baz':3"
// Prints "4: 'foo':1"

Resources