I use FCM to send push notification to my iOS app.When user click on the notification tray,the data handle by the function below:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
print(userInfo['data'])
}
The userInfo is a [AnyHashable:Any] type.I successfully get the data from the userInfo['data'].So here is the data structure for userInfo['data'] :
'{"data":
{
"title":"My app",
"message":"The message here",
"payload":{
"post_id":"602"
},
"timestamp":"2018-03-10 14:12:08"
}
}'
Here is how I tried :
if let dataString = userInfo["data"] as? String {
let data = dataString.data(using: .utf8)!
do {
if let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? [String : Any]
{
let message = json["message"] as? String ?? "No message here"
let title = json["title"] as String ?? ""
//here is the problem..I have no idea to do it here
let payload = json["payload"] as? [String : Int] ?? [:]
for element in payload {
if let postId = element["post_id"] {
//print("postId = \(postId)")
}
}
} else {
print("bad json")
}
} catch let error as NSError {
print(error)
}
So as shown in above,I have no problem to get value of title,message and timestamp inside the data json.
But I have to idea how to get the value of post_id which is inside payload array.
So in this case,how to get the value of post_id from the data json above? Thanks.
Access post id like this
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: #escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
if let data = userInfo["data"] as? [String: Any],
let payload = data["payload"] as? [String: Any],
let postId = payload["post_id"] as? String{
print("post id \(postId)")
}else{
print("there is no post id inside the payload")
}
}
Related
For my project I want to parse an Alamofire JSON response and save it in Realm. I already tested this by fetching the JSON from a Mock-API and it worked fine, but when I'm trying to incorporate my Code into my AM-response handling I'm getting this error:
Invalid conversion from throwing function of type '(AFDataResponse) throws -> Void' (aka '(DataResponse<Any, AFError>) throws -> ()') to non-throwing function type '(AFDataResponse) -> Void' (aka '(DataResponse<Any, AFError>) -> ()')
The Code for the response looks like this:
.responseJSON { response in //this is where I'm getting the error
print(response)
self.books = [Books]()
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject] {
if let booksFromJson = json["books"] as? [[String : AnyObject]]{
for bookFromJson in booksFromJson {
let book = Books()
if let title = bookFromJson["title"] as? String, let author = bookFromJson["author"] as? String, let imageLink = bookFromJson["imageLink"] as? String {
book.author = author
book.title = title
book.imageLink = imageLink
}
self.books?.append(book)
}
This is my AM-Request as a whole:
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image:UIImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
self.myImage = image
AF.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(self.myImage.jpegData(compressionQuality: 0.5)!, withName: "image", fileName: "image.png", mimeType: "image/jpeg")
}, to: "https://booknerdvirtualreadinglist.herokuapp.com/getbook" , headers: nil )
.uploadProgress { progress in
print(progress)
}
.responseJSON { response in
print(response)
self.books = [Books]()
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject] {
if let booksFromJson = json["books"] as? [[String : AnyObject]]{
for bookFromJson in booksFromJson {
let book = Books()
if let title = bookFromJson["title"] as? String, let author = bookFromJson["author"] as? String, let imageLink = bookFromJson["imageLink"] as? String {
book.author = author
book.title = title
book.imageLink = imageLink
}
self.books?.append(book)
}
dismiss(animated: true, completion: nil)
}
Thank you in advance!
You are not catching the error correctly because your "try catch" only has a do block.
This is how you can properly handle an error in Swift:
do {
// some throwing code
} catch {
print("Failed with error \(error)")
}
The catch-part is missing.
I am new to Swift and trying basic JSON parsing by following tutorials. I want to print a field of a JSON file, but it is not working.
Although the link exists, and I am using the same link I used for a previous tutorial, it returns rather than moved on to accessing the JSON.
I understand there is an "easier" way to do it in Swift4 using Decoder, but I received an error when I did it that way.
Here is the structure I am using:
struct Tester {
var userId: Int
var id: Int
var title: String
var body: String
init(json: [String: Any]){
userId = json["userId"] as? Int ?? -10
id = json["id"] as? Int ?? -400
title = json["title"] as? String ?? ""
body = json["body"] as? String ?? ""
}
}
And here is the code that is trying to access the JSON entries
#IBAction func printIDTitle(_ sender: Any) {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else { return }
let session = URLSession.shared
session.dataTask(with: url) { (data, response, error) in
if let response = response {
print(response)
}
guard let data = data else { return }
do {
print("here 0\n")
guard let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
print(error)
return
}
print("here 0.5\n")
print("here 1\n")
let d = Tester(json: json)
print(d.id)
print(d.title)
print("here 2\n")
} catch let error {
print(error)
}
}.resume()
}
The "here 0" is the only print that shows up.
What could be my issue?
The root is an array so change
guard let json = try JSONSerialization.jsonObject(with: data, options:[]) as? [[String: Any]] else {
print(error)
return
}
Or better
let res = try! JSONDecoder().decode([Root].self, from:data)
struct Root: Codable {
let userId, id: Int
let title, body: String
}
I am trying to loop through a JSON array which I am getting from an HTTP Request, but I am not sure how.
What I have tried is this:
var request = NSMutableURLRequest(url: url! as URL, cachePolicy: NSURLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: Double.infinity)
if Reachability.isConnectedToNetwork(){
request = NSMutableURLRequest(url: url! as URL, cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: Double.infinity);
}
let session = URLSession.shared
var getResp = false
var zinnen : [Zin] = []
let task = session.dataTask(with: request as URLRequest,
completionHandler: { data, response, error -> Void in
let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
for case let data in json {
if let zin = Zin(json: data) {
zinnen.append(zin)
}
}
})
task.resume()
And this is my struct:
struct Zin : CustomStringConvertible {
var description: String
let id : Int
let dutch_sentence : String
let polish_sentence : String
init(dictionary: [String: Any]) {
self.id = dictionary["id"] as? Int ?? 0
self.dutch_sentence = dictionary["dutch_sentence"] as? String ?? ""
self.polish_sentence = dictionary["polish_sentence"] as? String ?? ""
}
}
A sample of the JSON Array:
[
{
"id":"35",
"dutch_sentence":"Ja",
"polish_sentence":"Tak"
},
{
"id":"36",
"dutch_sentence":"Nee",
"polish_sentence":"Nie"
}
]
But in this I get the error
Type '[String: Any]??' does not conform to protocol 'Sequence'
Don't ignore the error! Both try? and optional downcast cause a nested optional (Optional<Optional<[String:Any]>>) which of course is not a sequence, not even when being casted to an array.
Handle the error, optional bind the result and cast the result to the more specified array [[String:String]]. According to the JSON the value for id is String not Int.
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [[String: String]] {
for zinData in json {
let zin = Zin(dictionary: zinData)
zinnen.append(zin)
}
}
} catch { print(error) }
PS: The initializer in the Zin class does not match the initializer in the parsing code. I'm using the version of the class. You have to change the type of id from Int to String
I'm having a problem with the following code. I'm downloading a list of actors in JSON and I want to populate Struct Actor with the received data. Everything works great until I try to flatMap on the received data and try to initialize the struct Actor. When I try to compile the code i get the error: Cannot assign value of type '()' to type [Actor]. The error corresponds to a line in viewDidLoad actorsList = downloadActors() Would anybody have any recommendation who to solve this?
import UIKit
func downloadActors() {
var request = URLRequest(url: URL(string: "url...")!)
request.httpMethod = "POST"
let postString = "actorGroup=\("Superhero")"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
guard let data = data, error == nil else {
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
print("error : statusCode should be 200 but is \(httpStatus.statusCode)")
print("response = \(response)")
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode == 200 {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: AnyObject]
guard let actorsJSON = json?["response"] as? [[String : AnyObject]] else {
return
}
} catch {
print("catch error")
}
}
}
}
task.resume()
}
func loadActors() -> [Actor] {
if let actors = actorsJSON as? [[String : AnyObject]] {
return actors.flatMap(Actor.init)
}
}
let actorsArray = loadActors()
class MasterViewController: UITableViewController {
var actorsList = [Actor]()
var detailViewController: DetailViewController? = nil
var objects = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
actorsList = downloadActors()
print(actorsList)
Struct Actors is as follows:
struct Job {
let actorGroup: String
let actorName: String
}
extension Actor: JSONDecodable {
init?(JSON: [String : AnyObject]) {
guard let actorGroup = JSON["actorGroup"] as? String, let actorName = JSON["actorName"] as? String else {
return nil
}
self. actorGroup = actorGroup
self. actorName = actorName
}
}
let listActors = actorsJSON as? [[String : AnyObject]] {
Should be:
if let listActors = actorsJSON as? [[String : AnyObject]] {
Edit: For more info I'd like to add Vadian's comment:
Very confusing code. What does the function in the middle of the do block? Why do you type-check actorsJSON twice? The computed property is let listActors... which should be probably an optional binding (if let ... ). Further .mutableContainers is completely nonsense in Swift. And finally a JSON dictionary is [String:Any] in Swift 3.
I currently developing an app which list user object by making an request to a webservice, which send a response in JSON in this format :
{
"0":
{
"id":"30",
"title":"galaxys6",
"price":"550",
"description":"neuf",
"addedDate":"2015-07-16 15:04:24",
"user_id":"2",
"user_name":"",
"user_zipCode":"69003",
"category_id":"1",
"category_label":"PHONE",
"subcategory_id":"1",
"subcategory_label":"Phone",
"picture":"",
"bdd":{},
"picture_url":"http:\/\/jdl-barreme-orange.dyndns.org\/WEBSERVICE\/pictures\/galaxy s6.JPG"
},
"1":
{
"id":"31",
"title":"iphone4",
"price":"570",
"description":"neuf",
"addedDate":"2015-07-16 15:14:54",
"user_id":"2",
"user_name":"",
"user_zipCode":"69003",
"category_id":"1",
"category_label":"PHONE",
"subcategory_id":"1",
"subcategory_label":"Phone",
"picture":"",
"bdd":{},
"picture_url":"http:\/\/jdl-barreme-orange.dyndns.org\/WEBSERVICE\/pictures\/iphone.JPG"
},
}
For each object my webservice create a dictionary (0;1;2;3....)
I search a method to retrieve for each dictionary the value title and price and put them in a tableView.
Code I used (tableviewcontroller) :
if let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as? NSDictionary{
// 4
if let resp = jsonData["1"] as? [NSDictionary] {
NSLog("%#", resp)
// 5
for item in resp {
repositories.append(Repository(jsonData: item))
}
repository controller :
class Repository {
var name: String?
var description: String?
var html_url: String?
init(jsonData: NSDictionary) {
self.name = jsonData["id"] as? String
self.description = jsonData["description"] as? String
self.html_url = jsonData["title"] as? String
}
}
But it doesn't work, I put a breakpoint, and xcode stop to interpret here :
if let resp = jsonData["1"] as? [NSDictionary] {
NSLog("%#", resp)
What am I doing wrong?
Thank you.
Here's how to get the title and price for your JSON:
if let json = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [String:AnyObject] {
for (_, value) in json {
if let dict = value as? [String:AnyObject] {
if let title = dict["title"] as? String {
println(title)
}
if let price = dict["price"] as? String {
println(price)
}
}
}
}
This can also be used to init your Repository classes if you want:
class Repository {
var name: String?
var description: String?
var html_url: String?
init(jsonData: [String:AnyObject]) {
self.name = jsonData["id"] as? String
self.description = jsonData["description"] as? String
self.html_url = jsonData["title"] as? String
}
}
var repos = [Repository]()
if let json = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [String:AnyObject] {
for (_, value) in json {
if let dict = value as? [String:AnyObject] {
let repo = Repository(jsonData: dict)
repos.append(repo)
}
}
}
for repo in repos {
println(repo.name)
println(repo.description)
println(repo.html_url)
}
In the loop I'm ignoring the key: for (_, value) in json but you can use it if needed of course:
for (key, value) in json {
println(key) // "1", "2", ...
// ...
}
UPDATE:
Following your comment asking how to use this answer if your data format is different: if you want an array of dictionaries, change the typecast of the NSJSONSerialization result to reflect that: [[String:AnyObject]]. Next you can iterate over your array to get each dictionary properties:
if let jsonArray = NSJSONSerialization.JSONObjectWithData(urlData!, options: nil, error: nil) as? [[String:AnyObject]] {
for dict in jsonArray {
if let title = dict["title"] as? String {
println(title)
}
}
}
You are making a mistake here
if let resp = jsonData["1"] as? [NSDictionary]
This should be a NSDictionary not [NSDictionary], (which would be an array of dictionaries).
Also this conditional block
if let reposArray = jsonData["items"] as? [NSDictionary]
will never be executed because jsonData does not contain a key "items".
I guess it is the [NSDictionary]
if let resp = jsonData["1"] as? [NSDictionary]
[NSDictionary] is array of NSDictionary same as Array<NSDictionary>
just remove the brackets [] and change to
if let resp = jsonData["1"] as? NSDictionary