I'm very lost parsing the following response from an AF request – let json = result as! NSDictionary – in Swift:
{
errors = (
);
get = statistics;
parameters = {
country = germany;
};
response = (
{
cases = {
"1M_pop" = 14303;
active = 317167;
critical = 4179;
new = "+15161";
recovered = 863300;
total = 1200006;
};
continent = Europe;
country = Germany;
day = "2020-12-08";
deaths = {
"1M_pop" = 233;
new = "+380";
total = 19539;
};
population = 83900328;
tests = {
"1M_pop" = 347331;
total = 29141172;
};
time = "2020-12-08T09:15:08+00:00";
}
);
results = 1;
}
Any idea how to get the actual case numbers, i.e. for example the number of new cases?
So far I have tried the following (error throwing) approach:
if let responseDict = result as? NSDictionary {
if let data = responseDict.value(forKey: "response") as?
[NSDictionary] {
// Get case numbers
guard let cases = data[0]["cases"] else { return }
guard let casesPerOneMil = cases[0] as! Int else { return }
print(casesPerOneMil)
}
}
Basically don't use NS... collection types in Swift at all, use native types.
And don't use value(forKey, use key subscription.
And you have to conditional downcast Any to the expected concrete type.
There is another mistake: The object for cases is a dictionary, note the {} and you have to get the value for casesPerOneMil with key subscription, too
if let responseDict = result as? [String:Any],
let dataArray = responseDict["response"] as? [[String:Any]],
let firstDataItem = dataArray.first {
// Get case numbers
guard let cases = firstDataItem["cases"] as? [String:Any] else { return }
guard let casesPerOneMil = cases["1M_pop"] as? Int else { return }
print(casesPerOneMil)
}
}
Related
Is there anyway to insert entities with relationship? I get error "Illegal attempt to establish a relationship 'content' between objects in different contexts"
addUsers(users: [userData])
func addUsers(users: [User]) {
let taskContext = container.viewContext
taskContext.perform {
let batchInsertRequest = self.newBatchInsertRequest(with: users)
if let fetchResult = try? taskContext.execute(batchInsertRequest),
let batchInsertResult = fetchResult as? NSBatchInsertResult,
let success = batchInsertResult.result as? Bool, success {
return
}
}
}
crash happens in below code
private func newBatchInsertRequest(with users: [Users]) -> NSBatchInsertRequest {
var index = 0
let total = message.count
let batchInsertRequest = NSBatchInsertRequest(entity: WaUser.entity(), managedObjectHandler: { managedObject in
guard index < total else { return true }
let user = users[index]
if let waUser = managedObject as? WaUser {
waUser.name = user.name
let waUserInfo = waUserInfo(context: self.container.viewContext)
waUserInfo.pass = "12345"
waUserInfo.key = "asdfgh"
waUser.info = waUserInfo **//crash occurs here**
}
index += 1
return false
})
return batchInsertRequest
}
I'm trying to retrieve data from a Firebase RealTime database, in order to put it on a list which will be used to display data on a TableView.
My problem is that even if I get some data, I haven't enough knowledge to access on arrays and other swift objects. Perhaps, I'm not using the good way to do what I want.
Here is an example of a row on Firebase :
Here is a function written in Swift in which I'm trying to build a list for each row object.
func displayStationsUsingSearch(){
let station = self.stationName
let CP = Int(self.searchedCP!)
// create searchRef or queryRef you name it
let stationsRef = Database.database().reference().child("Stations")
stationsRef.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
/*if snapshot.value is NSNull {
print("not found")
} else {
// yes we got the user
let id = snapshot.value as! Int
}*/
for child in snapshot.children {
stationsRef.queryOrdered(byChild: "marque")
.queryEqual(toValue: "TOTAL ACCESS")
.observe(.value, with: { snap in
if let dict = snap.value as? [String: AnyObject] {
/*self.stationItem!.nomStation = dict["nomStation"] as! String
self.stationItem!.adresse = dict["adresse"] as! String
self.stationItem!.codePostal = dict["codePostal"] as! String
self.stationItem!.ville = dict["ville"] as! String
self.stationItem!.marque = dict["marque"] as! String
self.stationItem!.pays = dict["pays"] as! String
self.stationItem!.commentaire = dict["commentaire"] as! String
self.stationItem!.coordGPS = dict["coordGPS"] as! String*/
print(dict["nomStation"] as! String)
}
})
}
})
}
The lldb on Xcode workspace displays that :
Printing description of child:
Snap (-LdA6X8CfNY3bsPni31U) {
"DIESEL EXCELLIUM" = 0;
"DIESEL ULTIMATE" = 0;
GAZOLE = 0;
GPL = 0;
SP95 = 0;
"SP95 E10" = 0;
SP98 = 0;
SUPER = 0;
adresse = "RN1 Direction Moisselles";
codePostal = 95570;
commentaire = "";
coordGPS = "";
createdAt = "31/07/2018";
heureDebut = "";
heureFin = "";
id = 0;
marque = ESSO;
modifiedAt = "23/04/2019 18:53";
nomStation = "ESSO Moisselles";
pays = "";
saufJour = "";
services = "";
typeRoute = "";
ville = Moisselles;
}
(lldb)
Could you please help me to retrieve data on a list that I could append to display data on tableview ? Thank you.
Try something like that:
Database.database().reference()
.child("Stations").
observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else {
return
}
var stations = [Station]()
for (key, value) in values {
guard let station = value as? [String: Any],
let adresse = station["adresse"] as? String,
let codePostat = station["codePostat"] as? String else {
continue
}
stations.append(Station(adresse: adresse, codePostat: codePostat))
}
// if you have some completion return retrieved array of stations
completion(stations)
})
struct Station {
private let adresse: String
private let codePostat: String
init(adresse: String, codePostat: String) {
self.adresse = adresse
self.codePostat = codePostat
}
}
You can use a swift Class Instead.
Swift Object:
import Foundation
class FirebaseTransactionData : NSObject{
var customer : FirebaseTransactionDataCustomer!
var driver : FirebaseTransactionDataCustomer!
var status : String!
init(fromDictionary dictionary: [String:Any]){
status = dictionary["status"] as? String
if let customerData = dictionary["customer"] as? [String:Any]{
customer = FirebaseTransactionDataCustomer(fromDictionary: customerData)
}
if let driverData = dictionary["driver"] as? [String:Any]{
driver = FirebaseTransactionDataCustomer(fromDictionary: driverData)
}
}
}
class FirebaseTransactionDataCustomer : NSObject{
var lat : Double!
var longField : Double!
init(fromDictionary dictionary: [String:Any]){
lat = dictionary["lat"] as? Double
longField = dictionary["lng"] as? Double
}
}
Firebase Method
ref.observe(DataEventType.value, with: { (snapshot) in
let value = snapshot.value as? [String:Any]
let datt = FirebaseTransactionData(fromDictionary: value!)
print("snapshot \(datt.status!)")
print("snapshot \(datt.customer.lat!)")
})
I'm having some trouble with an array. I created an array called 'coins'
var coins = [Coin]()
then appended objects to it within a function
func getCoinData() {
AF.request("https://min-api.cryptocompare.com/data/top/mktcapfull?limit=10&tsym=USD", encoding: JSONEncoding.default).responseJSON { response in
if let json = response.result.value{
let responseDictionary = json as! [String : Any]
let data = responseDictionary["Data"] as! [Any]
for index in data {
let coin = index as! Dictionary<String, Any>
let coinInfo = coin["CoinInfo"] as! Dictionary<String, Any>
let displayInfo = coin["DISPLAY"] as! Dictionary<String, Any>
let usdDisplayInfo = displayInfo["USD"] as! Dictionary<String, Any>
let name = coinInfo["Name"]
let fullName = coinInfo["FullName"]
let imageUrl = coinInfo["ImageUrl"]
let price = usdDisplayInfo["PRICE"]
let marketCap = usdDisplayInfo["MKTCAP"]
let change24Hr = usdDisplayInfo["CHANGE24HOUR"]
let newCoin = Coin()
if let newCoinName = name, let newCoinFullName = fullName, let newCoinImageUrl = imageUrl, let newCoinPrice = price, let newCoinMarketCap = marketCap, let newCoinChange24hr = change24Hr {
let coinName = newCoinName
let coinFullName = newCoinFullName
let coinImageUrl = newCoinImageUrl
let coinPrice = newCoinPrice
let coinMarketCap = newCoinMarketCap
let coinChange24Hr = newCoinChange24hr
newCoin.name = "\(coinName)"
newCoin.fullName = "\(coinFullName)"
newCoin.imageURL = "\(coinImageUrl)"
newCoin.price = "\(coinPrice)"
newCoin.marketCap = "\(coinMarketCap)"
newCoin.change24Hr = "\(coinChange24Hr)"
self.coins.append(newCoin)
}
}
}
}
}
When i print 'self.coins.count' within the scope of the function i can see the count incrementing. Outside the function it's reading 0 items in the array.
Written for Swift 5
The problem is that you have a URL request which is Asynchronous. This means that the task is not waited for to complete.
In your problem, inside the function coins is printed after it has been assigned, after the URL request. However, when coins is printed outside the function, it is printed before it has been changed, as the URL request has not yet completed.
To solve this, you need to create a completion handler. A basic one is shown here:
// Our errors which could occur
enum SomeError: Error { case unknown }
// Function which is ASYNCHRONOUS
func someAsyncFunction(completion: #escaping (Result<Int, SomeError>) -> ()) {
// Temporary for this example
let success = true
let myNum = 3
// Return value if it is a success, otherwise return the error
if success {
completion(.success(myNum))
} else {
completion(.failure(.unknown))
}
}
// Call
someAsyncFunction { (result) in
print("Result: \(result)")
/* PRINT COINS HERE */
}
See a full guide on completion handlers using Result in Swift 5 at hackingwithswift.com.
How to separate values from an array using Swift 4. Following are my data:
arrWeekly == (
{
date = "2018-04-30";
units = "g/dL";
value = 12;
},
{
date = "2017-06-27";
units = "g/dL";
value = "14.5";
}
)
My Code:
if let arrMonthly = dictPeriod["monthly"] as? [Any], arrMonthly.count > 0
{
self.arrMonth = NSMutableArray(array: arrMonthly)
print("arrMonthly == ",self.arrMonth)
}else{
self.arrMonth = NSMutableArray()
}
I want to separate both dates & Values.
if let arrMonthly = dictPeriod["monthly"] as? [[AnyHasahble:String]], ! arrMonthly.isEmpty {
for disc in arrMonthly{
if let date = disc["date"] as? String{
}
if let units = disc["units"] as? String{
}
if let value = disc["value"] as? String{
}
}
}else{
}
let dictPeriod = YOUR_DICTIONARY
guard let arrMonthly = dictPeriod["monthly"] as? [[String: Any]], !arrMonthly.isEmpty else { return }
let dateArr = arrMonthly.map({ $0["date"] as! String })
let unitsArr = arrMonthly.map({ $0["units"] as! String })
let valueArr = arrMonthly.map({ $0["value"] as! String })
New to contacts trying to retrieve Mobile Phone number. I have address name email but cannot figure out mobile phone. This is what I got. The portion marked with ** is where I am going wrong.
if let oldContact = self.contactItem {
let store = CNContactStore()
do {
let mykeysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPostalAddressesKey,CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactPhoneNumbersKey]
let contact = try store.unifiedContactWithIdentifier(oldContact.identifier, keysToFetch: mykeysToFetch)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if contact.imageDataAvailable {
if let data = contact.imageData {
self.contactImage.image = UIImage(data: data)
}
}
self.fullName.text = CNContactFormatter().stringFromContact(contact)
self.email.text = contact.emailAddresses.first?.value as? String
self.phoneNumber.text = contact.phoneNumbers.first?.value as? String
**if contact.isKeyAvailable(CNContactPhoneNumbersKey){
if let phoneNum = contact.phoneNumbers.first?.value as? String {
self.phoneNumber.text = phoneNum as String
}
}**
if contact.isKeyAvailable(CNContactPostalAddressesKey) {
if let postalAddress = contact.postalAddresses.first?.value as? CNPostalAddress {
self.address.text = CNPostalAddressFormatter().stringFromPostalAddress(postalAddress)
} else {
self.address.text = "No Address"
}
}
})
} catch {
print(error)
}
}
If you want a list of the mobile phones for a contact, you look at phoneNumbers which is an array of CNLabeledValue, and find those with a label of CNLabelPhoneNumberMobile or CNLabelPhoneNumberiPhone.
For example, you could do something like:
let mobilePhoneLabels = Set<String>(arrayLiteral: CNLabelPhoneNumberMobile, CNLabelPhoneNumberiPhone, "cell", "mobile") // use whatever you want here; you might want to include a few strings like shown here to catch any common custom permutations user may have used
let mobileNumbers = contact.phoneNumbers.filter { mobilePhoneLabels.contains($0.label) && $0.value is CNPhoneNumber }
.map { ($0.value as! CNPhoneNumber).stringValue }
So if you want the first one:
let mobileNumber = mobileNumbers.first ?? "" // or use `if let` syntax
Or if you want a string representation of the list of them:
let mobileNumberString = mobileNumbers.joinWithSeparator(" ; ")
What you do with this array of mobile numbers is up to you, but hopefully this illustrates the basic idea.