swifty Json parse data show me nil? - ios

fail parsing data
let tag:string = "\(sender.tag)"
let name:string = (self.json?["data"][tag]["name"].stringValue)!
success parse data
let tag:Int = sender.tag
let name:String = (self.json?["data"]["\(tag)"]["name"].stringValue)!
what different about tag?

Sender tags only take Int values and they also give Int values. You simply just can't take tag as String and set it as String.
You can even test it without your parsig. Simply test it with buttons.

Related

Adding data to Firestore dynamically

Is it possible to add a dynamic amount of strings to Firestore?
This is my code:
I use a string array called names.
let newDoc = ref.collection("Docs").document()
for i in 0 ..< names.count{
newDoc.setData(["\(i)" : names[i]])
}
It's possible, but you probably don't want to be calling setData repetitively like that. Instead, you can translate names into a Dictionary<String,String> and then just call setData once:
let names = [String]()
let dictVersion = Dictionary(uniqueKeysWithValues: names.enumerated().map { index, value in
return ("\(index)",value)
})
let newDoc = ref.collection("Docs").document()
newDoc.setData(dictVersion)

Using A Variable Inside Firestore Call - Swift

I would like to use a variable inside a Firestore reference. I have a sub-collections stored on the database per shop and they all have the format 'menu Shop1' or 'menu Shop2'. I have to store it this way otherwise if I use menu alone, the collectionGroup reference points to all the menus and returns them all at once - which is not what I want.
I'm struggling to pass the name of the shop to the collectionGroup reference.
This does not work:
let shopName = String("Shop1")
let collectionRef = String("menu \(shopName!)")
let ref = db.collectionGroup((collectionRef!))
But then this works:
let ref = db.collectionGroup("menu Shop1")
I have tried all the variations I know and it still wont pass the string. Does anybody know how to fix this? I'm guessing its a small tweek!
I would just concatenate the string like so:
let shopName: String = "Shop1"
let refString: String = "menu " + shopName
let ref = db.collectionGroup(refString)
Don't forget the 'space' after "menu"
You could also simplify further like so:
let shopName: String = "Shop1"
let ref = db.collectionGroup("menu " + shopName)
The argument does not need to be hard coded...
There's no need for specifying 'String'
let shopName = String("Shop1")
Just make it
let shopName = "Shop1"
Then this is not correct if the intention is to actually create a ref to a collection
let collectionRef = String("menu \(shopName!)")
it should be
let shopsCollection = db.collection("shops")
or like this
let shopName = "shop1"
let thisShop = "menu " + shopName
let shopsCollectionGroup = db.collectionGroup(thisShop)
But... I am not sure you're using the collectionGroups correctly to start with based on the names you're using.
A collection group consists of all collections with the same ID, so for example you could have a collection group of 'shops' whereas yours is called 'menu Shop1' which would indicate a single shop. Or from the guide a collectionGroup called 'landmarks' which would include landmarks from multiple cities.
Read though the Collection Group Queries guide again to ensure it's being used correctly.
As a side note, please protect your code by handling optionals properly.
shopName!
is bad news is shopName is nil as it will crash you code. See nil-coelescing operators, guard and if statements.

Swift dictionary contains value but is not printed on the debugger console

I am creating and printing values in a dictionary like this
let answersToSubmit = SubmitAnswerModel() //main model
let realm = try! Realm()
let savedExamResponse = realm.object(ofType: SavedExamResponse.self, forPrimaryKey: id)
answersToSubmit.uniqid = savedExamResponse?.uniqueId
var answerListToSubmit = [QuestionAnswersToSubmit]()
for item in (savedExamResponse?.questionAnswerList)! {
let answerToSubmit = QuestionAnswersToSubmit()
answerToSubmit.qid = item.questionId
answerToSubmit.value.append(item.selectedOption)
answerListToSubmit.append(answerToSubmit)
}
answersToSubmit.answers = answerListToSubmit
print("length %s ",answersToSubmit.answers.count)//this is printing 100
print("answers to submit %s",answersToSubmit)//this is printing only the first part
The output is like this
length %s 100
answers to submit %s SubmitAnswerModel {
uniqid = test-5cb2f6a2d81034.66536499;
//the rest of the object needs to printed here, isn't it
}
So I am not quite sure if I have appended the array and put it in dictionary. Any help would be appreciated. Thanks
If you want a more comprehensive logging output try using the dump() function instead:
dump(answersToSubmit)
Which prints out a lot more information to the console.
Thats the expected output in your for statement. I'm not sure why your trying to append, realm doesn't handle arrays as such. You might need to use realm Lists if you need to store arrays.
But from the code you have shown this should work.
for item in (savedExamResponse?.questionAnswerList)! {
let answerToSubmit = QuestionAnswersToSubmit()
answerToSubmit.qid = item.questionId
answerToSubmit.value = item.selectedOption
answerListToSubmit = answerToSubmit
}

Firebase query hex codes contained within randomly generated keys

I would like to query a particular child from the array of color hex codes.
Here's a snapshot of my database structure:
How do I query a particular hex code and obtain the entire array of its parent object?
You cannot query whether a specific value exists in a list. This is one of the many reasons why the Firebase documentation recommends against using arrays in the database.
But in this case (and most cases that I encounter), you may likely don't really need an array. Say that you just care about what colors your user picked. In that case, you can more efficiently store the colors as a set:
palettes
-KSmJZ....A5I
"0x474A39": true
"0xbA9A7C": true
"0xDEDEDF": true
"0x141414": true
"0x323E35": true
I did it in a different way,
made a function that does this:
let databaseRef = FIRDatabase.database().reference()
let HEX1 = hex1.text! as String
let HEX2 = hex2.text! as String
let HEX3 = hex3.text! as String
let HEX4 = hex4.text! as String
let HEX5 = hex5.text! as String
let URL = url.text! as String
// First set
let colorArray1 = [HEX2, HEX3, HEX4, HEX5, URL]
databaseRef.child("palette").child(HEX1).setValue(colorArray1)
// second set
let colorArray2 = [HEX1, HEX3, HEX4, HEX5, URL]
databaseRef.child("palette").child(HEX2).setValue(colorArray2)
// third set
let colorArray3 = [HEX1, HEX2, HEX4, HEX5, URL]
databaseRef.child("palette").child(HEX3).setValue(colorArray3)
// fourth set
let colorArray4 = [HEX1, HEX2, HEX3, HEX5, URL]
databaseRef.child("palette").child(HEX4).setValue(colorArray4)
// fifth set
let colorArray5 = [HEX1, HEX2, HEX3, HEX4, URL]
databaseRef.child("palette").child(HEX5).setValue(colorArray5)
so that when I target any of the 5 hexes, it will bring me back the whole array together with it.

`CountedSet` initialization issue

I'm comparing the characters contained within two words. In seeking to accomplish this, Set (aka NSSet) seemed like the way to go to accomplish this task. I've discovered it returns false positives on matches, so I am attempting to use CountedSet (aka NSCountedSet) instead.
I'm able to initialize a Set without issue, but I can't get the CountedSet initializer to work. Here's what I've done...
I start with a String:
// Let's say myTextField.text = "test"
let textFieldCharacters = myTextField.text?.characters
// word is a string from the ENABLE list of words
let wordCharacters = word.characters
Then I dump the characters into an Array:
var wordCharactersArray = [Character]()
for character in wordCharacters {
wordCharacterArray.append(character)
}
var textFieldCharactersArray = [Character]()
for character in textFieldCharacters {
wordCharacterArray.append(character)
}
Then I create a Set from the character arrays:
let textFieldSet = Set<Character>(textFieldCharactersArray)
let wordSet = Set<Character>(wordCharactersArray)
Finally, I test to see if the textFieldSet is a superSet of wordSet with the following:
textFieldSet.isSuperset(of: wordSet)
Going back to my example, if myTextField.text is "test", I'm returning values for word whose characters are a superset of the wordSet, but the counts of the individual elements don't match the character counts of myTextField.text
In researching my issue, I've found CountedSet (fka NSCountedSet), which I think would resolve my issue. It has two method signatures:
public convenience init(array: [AnyObject])
public convenience init(set: Set<NSObject>)
I've tried initializing the 2 sets of characters like so:
let textFieldSet = CountedSet(array: textFieldCharacterArray)
let wordSet = CountedSet(array: wordCharacterArray)
I get the following error for the sets
Cannot convert value of type '[Character]' to expected argument type
'[AnyObject]'.
So I tried initializing the set like this:
let textFieldSet = CountedSet(array: textFieldCharacterArray as! [AnyObject])
Which yields the following error:
'AnyObject' is not a subtype of 'Character'
I've also tried to initialize the CountedSet with a Set, per the method signature, but I get errors when I try to do that, too.
Any suggestions how to initialize a CountedSet would be greatly appreciated.
You are correct that if you need to compare not just the presents of elements but also their count, you should use CountedSet, which is a renaming of NSCountedSet for swift 3.0. The problem you are running into is CountedSet can only accept elements that are objects and Characters are not. As Eric D points out in their comment, the easies way to get around this is by mapping your [Character] to [String] which will bridge to [NSString].
You are not running into this problem using Set, because it is a native Swift collection type that initialize with elements of any type. This is why you can initialize a Set with [Character].
To see the difference:
let word = "helo"
let wordCharacters = Array(word.characters)
let wordSet = Set(wordCharacters)
let wordCharStrings = wordCharacters.map{String($0)}
let wordCountedSet = CountedSet(array: wordCharStrings)
let textField = "hello"
let textFieldCharacters = Array(textField.characters)
let textSet = Set(textFieldCharacters)
let textFieldCharStrings = textFieldCharacters.map{String($0)}
let textFieldCountedSet = CountedSet(array: textFieldCharStrings)
textFieldCountedSet.isSubset(of: wordCountedSet as! Set<NSObject>) // returns false, but if word had two or more l's it would return true
textSet.isSubset(of: wordSet) // returns true

Resources