I need to log items in carts but I can't figure out how to do that. In Swift it is not allowed to use append() function, so I tried to create a dictionary inside an array but with this method it does not work properly, I got an error in Firebase Debugview. Here is my codes: (Swift, iOS)
func logViewCart(items: [CartItem]){
var itemList : [[String : Any]] = []
for item in items{
var itemParams : [String : Any] = [
"item_id": item.id,
"item_name": item.product?.name,
"item_category": item.product.category,
"price": item.price
]
itemList.append(itemParams)
}
var itemTest : [String : Any] = [:]
for i in itemList {
itemTest[AnalyticsParameterItems] = [i]
}
Analytics.logEvent("view_cart", parameters: [
"items": [itemTest]
])
}
Thanks in advance
There's several ways for the error you are getting, you can start by typing the log message or the behaviour.
I'll go first for the basics on login an event, make sure you have this property set -FIRAnalyticsDebugEnabled on your scheme like so
With that should popUp like in 3~6 seconds on the debug viewer, then make sure you have the parameters right.
I found the solution. Instead of declaring a dictionary inside an array, declaring another array variable with [Any] type solve the problem.
var itemList : [Any] = []
for item in items{
let variantIndex = item.product?.attributes?[1].listValueLabel?.count ?? 1
var itemParams : [String : Any] = [
"item_id": item.itemID,
"item_name": item.product?.name
]
itemList.append(itemParams)
}
Analytics.logEvent("view_cart", parameters: [
AnalyticsParameterItems: itemList
])
Related
Recently, I've implemented Firebase Analytics AnalyticsEventBeginCheckout event.
But it seems AnalyticsParameterItems not be sent to Firebase.
My code :
var jeggings: [String: Any] = [
AnalyticsParameterItemID: "SKU_123",
AnalyticsParameterItemName: "jeggings",
AnalyticsParameterItemCategory: "pants",
AnalyticsParameterItemVariant: "black",
AnalyticsParameterItemBrand: "Google",
AnalyticsParameterPrice: 9.99,
]
// A pair of boots
var boots: [String: Any] = [
AnalyticsParameterItemID: "SKU_456",
AnalyticsParameterItemName: "boots",
AnalyticsParameterItemCategory: "shoes",
AnalyticsParameterItemVariant: "brown",
AnalyticsParameterItemBrand: "Google",
AnalyticsParameterPrice: 24.99,
]
var checkoutParams: [String: Any] = [
AnalyticsParameterCurrency: "USD",
AnalyticsParameterValue: 14.98,
AnalyticsParameterCoupon: "SUMMER_FUN"
];
checkoutParams[AnalyticsParameterItems] = [jeggings, boots]
// Log checkout event
Analytics.logEvent(AnalyticsEventBeginCheckout, parameters: checkoutParams)
This code is the tutorial code from Firebase.
It seems AnalyticsParameterItems not been send, but if I send item_id and item_name, these 2 fields appear on my event datas
Any solution ?
I have a nested Dictionary required to save in UserDefaults and share to extension. The dictionary structure like below:
let dict = [
"Sections" : [
["Title" : "Title1", "Items": ["item1-1", "item1-2", "item1-3"]],
["Title" : "Title2", "Items": ["item2-1", "item2-2", "item2-3", "item2-4"]],
["Title" : "Title3", "Items": ["item3-1"]],
]
]
Which saved successfully with:
UserDefaults(suiteName: "group.identifier.test")!.setValue(dict, forKey: "savedDict")
But now I wish to get it back and check is Title2 already exists, if yes then delete it and add again with new Items
I used to do following but can't get the Title back:
let savedDict:[String:AnyObject] = UserDefaults(suiteName: "group.identifier.test")!.object(forKey: "savedDict") as! Dictionary
success to get the data under "Sections" by following code
let savedSection = savedDict["Sections"]
print("Saved Section: \(savedSection)")
but not able to get the Title with:
print("Saved Title: \(savedSection!["Title"])") *// return nil*
I tried for (key, value) too, but fired a data type error
for (key, value) in savedSection{ *// Type 'AnyObject?' does not conform to protocol 'Sequence'*
print("Key: \(key) Value: \(value)")
}
May I know is there any way to get the "Title" back for checking and update? Am I using the wrong way to store this kind of nested data?
Many Thanks!
in your code
print("Saved Title: \(savedSection!["Title"])") *// return nil*
here it should be
if let savedSection = savedDict["Sections"] as? [[String : Any]] { //EDIT***
print("Saved Title: \(savedSection[0]["Title"])") *// inplace of 0 any index you want,
}
as if now in your dictionary there are three elements in section so it safe to get value at 0, hope you understood that the underlying dictionary is array of dictionary in sections key, also instead of using dictionary you can use struct or class to save your data and while getting it retrieve it as that struct type.
First of all, never use KVC method setValue(:forKey with UserDefaults.
There is generic set(:forKey. And there is dictionary(forKey: to get a [String:Any] dictionary back
The value for key Sections is an array (index-based). Lets assume you have this new data
let newTitle2 : [String:Any] = ["Title" : "Title2", "Items": ["item4-1", "item4-2", "item4-3"]]
This is a way to load the dictionary – you should always safely check if the dictionary exists – update it and save it back. If the item for "Title2" exists it will be overwritten otherwise the new item is appended to the array.
let groupDefaults = UserDefaults(suiteName: "group.identifier.test")!
if var savedDict = groupDefaults.dictionary(forKey: "savedDict"),
var sections = savedDict["Sections"] as? [[String:Any]] {
if let title2Index = sections.firstIndex(where: {($0["Title"] as! String) == "Title2"}) {
sections[title2Index] = newTitle2
} else {
sections.append(newTitle2)
}
savedDict["Sections"] = sections
groupDefaults.set(savedDict, forKey: "savedDict")
}
I 'm having an array of dictionary like so...
[
{
"id" : "3",
"sellingPrice" : "520",
"quantity" : "15"
},
{
"id" : "5",
"sellingPrice" : "499",
"quantity" : "-1"
},
{
"id" : "8",
"sellingPrice" : "500",
"quantity" : "79"
}
]
Now I want to add to the dictionary another key called remaining_balance with a value of 420,499 & 500 respectively. How can I achieve this..? Hope somebody can help...
It seems like you want to add a value to your dictionary that is an array:
var arrDict = Array<Dictionary<String,Any>>() //Your array
arrDict.append(["id":"3","sellingPrice":"520","quantity":"13"])
arrDict.append(["id":"5","sellingPrice":"43","quantity":"32"])
arrDict.append(["id":"8","sellingPrice":"43","quantity":"33"])
let arrValue = ["420","499","500"] //Your remaining value in array
print("Before ",arrDict)
for (index,dict) in arrDict.enumerated() {
var dictCopy = dict //assign to var variable
dictCopy["remaining_balance"] = arrValue[index]
arrDict[index] = dictCopy //Replace at index with new dictionary
}
print("After ",arrDict)
EDIT
If you are able keep an index of an array it would be possible,
Assuming that you have the index of an array
var dictCopy = arrDict[index]
dictCopy["remaining_balance"] = "666" //Your calculated value
arrDict[index] = dictCopy //Replace at index with new dictionary
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
let array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
let newArray = array.enumerated().map { (index : Int, value: [String: String]) -> [String: String] in
var dic = value
dic.merge(newKV[index]) { (_, new) -> String in
new
}
return dic
}
You could achieve it by mapping your array:
var myArray = [["id": "3", "sellingPrice": "520", "quantity" : "15"], ["id": "5", "sellingPrice": "499", "quantity" : "-1"], ["id": "8", "sellingPrice": "500", "quantity" : "79"]]
print(myArray)
/*
[["id": "3", "sellingPrice": "520", "quantity": "15"],
["id": "5", "sellingPrice": "499", "quantity": "-1"],
["id": "8", "sellingPrice": "500", "quantity": "79"]]
*/
print("___________________")
var remainingBalanceDesriedValue = 420
myArray = myArray.map { (dict: [String: String]) -> [String: String] in
var copyDict = dict
copyDict["remaining_balance"] = "\(remainingBalanceDesriedValue)"
remainingBalanceDesriedValue = (remainingBalanceDesriedValue == 420) ? 499 : (remainingBalanceDesriedValue == 499) ? 500 : 420
return copyDict
}
print(myArray)
/*
[["sellingPrice": "520", "quantity": "15", "id": "3", "remaining_balance": "420"],
["sellingPrice": "499", "quantity": "-1", "id": "5", "remaining_balance": "499"],
["sellingPrice": "500", "quantity": "79", "id": "8", "remaining_balance": "500"]]
*/
Let's assume you have an array of dictionaries like so:
var arrayOfDictionaries = [
[
"id": 3,
"sellingPrice": 520,
"quantity": 15
]
]
It is important that arrayOfDictionaries is not a let constant, otherwise it is considered immutable and you can not call append on it.
Now you init a new dictionary like:
let newDictionary = [
"id": 10,
"remaining_balance": 420,
"quantity": 15
]
Now add the newDictionary like
arrayOfDictionaries.append(newDictionary)
If the order is important
If the order is important there are a couple of ways to go about that.
When calling append the new value (in this case the new dictionary) will always be inserted at the bottom of the array.
If for some reason you can not call append in the correct order you could use insert, which inserts your dictionary at a specific position.
Yet another way is to append the values wildly and after you are done, call sort on the array.
Improvement Tips
Notice that for the values I did not use strings, as you only have numbers like "id" : 30.
Also, if you want the second key to be called remaining_balance you should call the first key selling_price instead of sellingPrice. Because of conistency.
Alternative approach
As far as I have understood you are trying to implement some software that is responsibly for selling some products.
I think you are tackling this problem from a completely wrong side.
I think you should read about database relationships. Selling products actually is a very common problem.
Maybe this will help you. I would offer a possible solution myself, but I think this misses the point of your question.
If you decide to use the database approach, you won't necessarily have to use a database. You can take the approach and implement it using simple structs/classes/arrays.
I noticed this question lacks an extension answer, yes.. I'm gonna be that guy, so here it is. This could be made more generic by supporting other types of dictionaries, feel free to pitch in ;)
Inspiration from #eason's answer.
var newKV = [["remaining_balance": "420"],["remaining_balance": "490"],["remaining_balance": "500"]]
var array = [["id":"3", "sellingPrice":"520", "quantity":"15"], ["id":"5", "sellingPrice":"520", "quantity":"15"], ["id":"8", "sellingPrice":"520", "quantity":"15"]]
extension Array where Element == [String: String] {
enum UniquingKeysStrategy {
case old
case new
}
mutating func merge(with target: Array<Element>, uniquingKeysWith: UniquingKeysStrategy = .new) {
self = self.merged(with: target)
}
func merged(with target: Array<Element>, uniquingKeysWith strategy: UniquingKeysStrategy = .new) -> Array<Element> {
let base = self.count > target.count ? self : target
let data = self.count > target.count ? target : self
return data.enumerated().reduce(into: base, {
result, data in
result[data.offset]
.merge(data.element, uniquingKeysWith: {
old, new in
if strategy == .new { return new }
return old
})
})
}
}
let mergedArrays = newKV.merged(with: array, uniquingKeysWith: .old)
array.merge(with: newKV)
Happy Coding :)
I'm having trouble creating a specific structure in JSON with Swift. I use Swifty JSON for parsing but I can't figure out how to create one.
I have this array which is filled by Id's and quantity Ints of products in a shopping basket . I need to get the array into my JSON but I don't know how.
If you could help me with this I would be very glad :)
var productArray = Array<(id: Int,quantity: Int)>()
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": [
for product in productArray
{
"id": product.id
"quantity": product.quantity
}
]
]
You can't just start looping through stuff while defining your dictionary. Here's another approach.
First, create your array:
var productArray = Array<(id: Int,quantity: Int)>()
Add some products (for testing):
productArray += [(123, 1000)]
productArray += [(456, 50)]
Map this array into a new array of dictionaries:
let productDictArray = productArray.map { (product) -> [String : Int] in
[
"id": product.id,
"quantity": product.quantity
]
}
Use the new mapped array in your JSON object:
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": productDictArray
]
You are not supposed to do any kind of looping/condition making block of codes while creating Array's or Dictionary. For that you need to execute that piece of code outside, create a variable and use it.
Do try this way.
var productArray = Array<(id: Int,quantity: Int)>()
var prods = [[String:Int]]()
for product in productArray
{
var eachDict = [String:Int]()
eachDict["id"] = product.id
eachDict["quantity"] = product.quantity
prods.append(eachDict)
}
let jsonObject: [String: AnyObject] = [
"order": 1,
"client" : 1,
"plats": prods
]
I'm trying to add multiple objects to NSDictionary, like
var myDict: NSDictionary = [["fname": "abc", "lname": "def"], ["fname": "ghi", "lname": "jkl"], ...]
Is it even possible to do this? If not, please suggest a better way. I actually need to convert this NSDictionary to JSON string and send that to the server, so I need multiple objects in NSDictionary.
You can definitely make a dictionary of dictionaries. However, you need a different syntax for that:
var myDictOfDict:NSDictionary = [
"a" : ["fname": "abc", "lname": "def"]
, "b" : ["fname": "ghi", "lname": "jkl"]
, ... : ...
]
What you have looks like an array of dictionaries, though:
var myArrayOfDict: NSArray = [
["fname": "abc", "lname": "def"]
, ["fname": "ghi", "lname": "jkl"]
, ...
]
To get JSON that looks like this
{"Data": [{"User": myDict1}, {"User": myDict1},...]}
you need to add the above array to a dictionary, like this:
var myDict:NSDictionary = ["Data" : myArrayOfDict]
SWIFT 3.0
List item
Frist of all you can create NSArray and Then you can Set Array in NSMutableDictionary using setvalue(forKey:) default method.
var arrFname : NSArray!
arrFname = ["abc","xyz","mno"]
var arrLname : NSArray!
arrFname = ["tuv","xuv","swift"]
var dicSet : NSMutableDictionary!
dicSet.setObject(arrFname, forKey : "Fname")
dicSet.setObject(arrLname, forKey : "Lname")
print(dicSet)
var tempDict = NSMutableDictionary()
tempDict.setValue("sam", forKey : "one")
print(tempDict["one"] ?? "1")