Swift - add text to dictionary - swift

While I am trying to add a value to a dictionary, it always fail while I try to set the value from my textField.text. I have a text field, that I want to add to a dictionary, with this code:
var dict = [String:AnyObject]()
dict.updateValue(usernameText.text!, forKey: "key")
print(dict["key"]!)
However, on the print it doesn't show anything. When I am setting the value as "a value" - it prints fine. How come I can't add a text field value?

What type is usernameText ? and are you certain that there is any text in it ?
try adding print(usernameText.text!) to make sure.
I tested with UITextField and could not reproduce the problem when there is text in the .text property.

Try it like this:
dict["key"] = usernameText.text!
Update:
Just tried this code:
var dict = [String:AnyObject]()
dict.updateValue("Foo", forKey: "key")
print(dict["key"]!)
and it prints me as I expected Foo, try the following code, setting non optional value under "key" key:
if let aText = usernameText.text {
dict.updateValue(aText, forKey: "key")
}

Related

Write to Nested Dictionary (Swift 4)

I have declared a dictionary in Swift as so: var dict = [String: [String: [String]]]().
What I am trying to do now is to write to the nested dictionary. I have used both codes below, however, none of them work as the initial key does not exist:
dict["Test"]?["One"] = ["Failed"]
dict["Test"]!["One"] = ["Failed"]
What I am trying to do is to create a key for ["One"], much like how you can create a key for a normal dictionary using dict[key].
You need to instantiate every inner dictionary.
var dict = [String : [String : [String]]]()
dict["Test"] = [String : [String]]()
dict["Test"]?["One"] = ["Worked"]
print(dict)
Make sure to avoid force unwrapping.
dict is empty. There is no value for the "Test" key.
One option is to provide a default:
dict["Test", default: [:]]["One"] = ["A", "B"]
You can take this one step further:
dict["Test2", default: [:]]["Two", default: []].append("Hello")
That last line will work for any combination of the keys "Test2" and "Two" existing or not before that is used.

How to pass and get multiple URLQueryItems in Swift?

Ok, I am working in an iMessage app and am trying to parse more than 1 url query item from the selected message here- I have been successful getting/sending just 1 value in a query:
override func willBecomeActive(with conversation: MSConversation) {
// Called when the extension is about to move from the inactive to active state.
// This will happen when the extension is about to present UI.
if(conversation.selectedMessage?.url != nil) //trying to catch error
{
let components = URLComponents(string: (conversation.selectedMessage?.url?.query?.description)!)
//let val = conversation.selectedMessage?.url?.query?.description
if let queryItems = components?.queryItems {
// process the query items here...
let param1 = queryItems.filter({$0.name == "theirScore"}).first
print("***************=> GOT IT ",param1?.value)
}
}
When I just have 1 value, just by printing conversation.selectedMessage?.url?.query?.description I get an optional with that 1 value, which is good. But with multiple I cant find a clean way to get specific values by key.
What is the correct way to parse a URLQueryItem for given keys for iMessage?
When you do conversation.selectedMessage?.url?.query?.description it simply prints out the contents of the query. If you have multiple items then it would appear something like:
item=Item1&part=Part1&story=Story1
You can parse that one manually by splitting the string on "&" and then splitting the contents of the resulting array on "=" to get the individual key value pairs in to a dictionary. Then, you can directly refer to each value by key to get the specific values, something like this:
var dic = [String:String]()
if let txt = url?.query {
let arr = txt.components(separatedBy:"&")
for item in arr {
let arr2 = item.components(separatedBy:"=")
let key = arr2[0]
let val = arr2[1]
dic[key] = val
}
}
print(dic)
The above gives you an easy way to access the values by key. However, that is a bit more verbose. The way you provided in your code, using a filter on the queryItems array, is the more compact solution :) So you already have the easier/compact solution, but if this approach makes better sense to you personally, you can always go this route ...
Also, if the issue is that you have to write the same filtering code multiple times to get a value from the queryItems array, then you can always have a helper method which takes two parameters, the queryItems array and a String parameter (the key) and returns an optional String value (the value matching the key) along the following lines:
func valueFrom(queryItems:[URLQueryItem], key:String) -> String? {
return queryItems.filter({$0.name == key}).first?.value
}
Then your above code would look like:
if let queryItems = components?.queryItems {
// process the query items here...
let param1 = valueFrom(queryItems:queryItems, key:"item")
print("***************=> GOT IT ", param1)
}
You can use iMessageDataKit library. It makes setting and getting data really easy and straightforward like:
let message: MSMessage = MSMessage()
message.md.set(value: 7, forKey: "user_id")
message.md.set(value: "john", forKey: "username")
message.md.set(values: ["joy", "smile"], forKey: "tags")
print(message.md.integer(forKey: "user_id")!)
print(message.md.string(forKey: "username")!)
print(message.md.values(forKey: "tags")!)
(Disclaimer: I'm the author of iMessageDataKit)

Swift Optional Dictionary [String: String?] unwrapping error

So here I have a basic setup
var preferenceSpecification = [String : String?]()
preferenceSpecification["Key"] = "Some Key"
preferenceSpecification["Some Key"] = nil
preferenceSpecification["DefaultValue"] = "Some DefaultValue"
print(preferenceSpecification)
var defaultsToRegister = [String : String]()
if let key = preferenceSpecification["Key"], let defaultValueKey = preferenceSpecification["DefaultValue"] {
defaultsToRegister[key] = preferenceSpecification[defaultValueKey]!
}
But the error points out where it demands that I force unwrap this, to be like this:
defaultsToRegister[key!] = preferenceSpecification[defaultValueKey!]!
Which doesn't make sense, because keyValue and defaultValue already are unwrapped
When you extract a value from a dictionary like this using subscript
[String: String?]
you need to manage 2 levels of optional. The first one because the subscript returns an optional. The second one because the value of you dictionary is an optional String.
So when you write
if let value = preferenceSpecification["someKey"] {
}
you get value defined as an optional String.
Here's the code to fix that
if let
optionalKey = preferenceSpecification["Key"],
key = optionalKey,
optionalDefaultValueKey = preferenceSpecification["DefaultValue"],
defaultValueKey = optionalDefaultValueKey,
value = preferenceSpecification[defaultValueKey] {
defaultsToRegister[key] = value
}
Suggestions
You should avoid force unwrapping as much as possible. Instead you managed to put 3 ! on a single line!
You should also try to use better name for your constants and variables.
You could also define an extension which helps get rid of the double optional situation.
extension Dictionary where Value == Optional<String> {
func flattened(_ key: Key) -> Value {
if let value = self[key] {
return value
}
return nil
}
}
Usage: preferenceSpecification.flattened("someKey")

Saving more than one value to a Dictionary key in a loop with an Array

I have this block of code
//start of the loop
if let objects = objects as? [PFObject] {
for object in objects {
//saving the object
self.likerNames.setObject(object["fromUserName"]!, forKey: saveStatusId!)
}
}
likerNames is an NSMutableArray declared earlier, saveStatusId is a string I also declared and saved earlier (It's just an objectId as a String), and object["fromUserName"] is an object returned from my query (not shown above).
Everything is working fine as it is but my query sometimes returns more than one object["fromUserName"] to the same key which is saveStatusId. When this happens the value I have for that saveStatusId is replaced when I actually want it to be added to the key.
So want it to kind of look like this
("jKd98jDF" : {"Joe", "John"})
("ksd6fsFs" : {"Sarah"})
("payqw324" : {"Chris", "Sarah", "John"})
I know you can use Arrays but I'm not sure how I would go about that to get it to work in my current situation.
So my question would be how to I get my key (saveStatusId) to store more than one value of object["fromUserName"]?
Something like this could work
let key = saveStatusId!
let oldValue = self.likerNames.objectForKey( key ) as? [String]
let newValue = (oldValue ?? []) + [ object["fromUserName" ] ]
self.likerNames.setObject( newValue, forKey: key )
If likerNames has an array in slot[saveStatusId], append the new value, otherwise create an array and put that in the right slot

Error when using NSUserDefaults

I've been trying for weeks now to save some values in one view controller then access them in another using the NSUserDefaults method. I am using this code:
(to save):
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("Coding Explorer", forKey: "userNameKey")
the last line produces an "expected declaration" error
(to get values):
let defaults = NSUserDefaults.standardUserDefaults()
if let name = defaults.stringForKey("userNameKey")
{
println(name)
}
The first of these lines produces a "incorrect redeclarion of 'defaults'"
second line produces "expected declaration"
third line produces "Consecutive declarions on a line must be seperated by a ;" and "variables used within its own initial value"
Please help me fix this I've tried different lots of code to use NSUserDefaults, and I've tried using the code on separate and the same view controllers.
You may try to use this way..
to save first define a string called for example "firstName":
var firstName : String = "Im Swift"
in viewDidLoad in the first ViewController :
if (NSUserDefaults.standardUserDefaults().stringForKey("firstName") == nil){
NSUserDefaults.standardUserDefaults().setObject(firstName, forKey: "firstName")
}
To retrieve value :
in the viewDidLoad of second ViewController :
if (NSUserDefaults.standardUserDefaults().stringForKey("firstName") != nil){
var x = NSUserDefaults.standardUserDefaults().objectForKey("firstName") as! String
println("\(x)");
}