I'm using Alamofire to get emails from the Gmail API via the message IDs:
AF.request("https://www.googleapis.com/gmail/v1/users/me/messages/\(id)?format=full", headers: headers)
.responseJSON { [self] response in
do {
let json = try JSON(data: response.data!)
if let rawString = json.rawString() {
let email = try Email(rawString)
} else {
print("json.rawString is nil")
}
emailFetchGroup.leave()
}
catch {
print(error)
emailFetchGroup.leave()
}
}
And I have the following class, Email, that I'm trying to create from via the JSON response:
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let email = try Email(json)
import Foundation
// MARK: - Email
class Email: Codable {
let sizeEstimate: Int
let historyID, threadID: String
let payload: Payload
let internalDate, snippet, id: String
let labelIDS: [String]
enum CodingKeys: String, CodingKey {
case sizeEstimate
case historyID = "historyId"
case threadID = "threadId"
case payload, internalDate, snippet, id
case labelIDS = "labelIds"
}
init(sizeEstimate: Int, historyID: String, threadID: String, payload: Payload, internalDate: String, snippet: String, id: String, labelIDS: [String]) {
self.sizeEstimate = sizeEstimate
self.historyID = historyID
self.threadID = threadID
self.payload = payload
self.internalDate = internalDate
self.snippet = snippet
self.id = id
self.labelIDS = labelIDS
}
}
// MARK: Email convenience initializers and mutators
extension Email {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Email.self, from: data)
self.init(sizeEstimate: me.sizeEstimate, historyID: me.historyID, threadID: me.threadID, payload: me.payload, internalDate: me.internalDate, snippet: me.snippet, id: me.id, labelIDS: me.labelIDS)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
sizeEstimate: Int? = nil,
historyID: String? = nil,
threadID: String? = nil,
payload: Payload? = nil,
internalDate: String? = nil,
snippet: String? = nil,
id: String? = nil,
labelIDS: [String]? = nil
) -> Email {
return Email(
sizeEstimate: sizeEstimate ?? self.sizeEstimate,
historyID: historyID ?? self.historyID,
threadID: threadID ?? self.threadID,
payload: payload ?? self.payload,
internalDate: internalDate ?? self.internalDate,
snippet: snippet ?? self.snippet,
id: id ?? self.id,
labelIDS: labelIDS ?? self.labelIDS
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Payload
class Payload: Codable {
let mimeType: String
let headers: [Header]
let body: Body
let partID, filename: String
enum CodingKeys: String, CodingKey {
case mimeType, headers, body
case partID = "partId"
case filename
}
init(mimeType: String, headers: [Header], body: Body, partID: String, filename: String) {
self.mimeType = mimeType
self.headers = headers
self.body = body
self.partID = partID
self.filename = filename
}
}
// MARK: Payload convenience initializers and mutators
extension Payload {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Payload.self, from: data)
self.init(mimeType: me.mimeType, headers: me.headers, body: me.body, partID: me.partID, filename: me.filename)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
mimeType: String? = nil,
headers: [Header]? = nil,
body: Body? = nil,
partID: String? = nil,
filename: String? = nil
) -> Payload {
return Payload(
mimeType: mimeType ?? self.mimeType,
headers: headers ?? self.headers,
body: body ?? self.body,
partID: partID ?? self.partID,
filename: filename ?? self.filename
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Body
class Body: Codable {
let size: Int
let attachmentID: String
enum CodingKeys: String, CodingKey {
case size
case attachmentID = "attachmentId"
}
init(size: Int, attachmentID: String) {
self.size = size
self.attachmentID = attachmentID
}
}
// MARK: Body convenience initializers and mutators
extension Body {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Body.self, from: data)
self.init(size: me.size, attachmentID: me.attachmentID)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
size: Int? = nil,
attachmentID: String? = nil
) -> Body {
return Body(
size: size ?? self.size,
attachmentID: attachmentID ?? self.attachmentID
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Header
class Header: Codable {
let name, value: String
init(name: String, value: String) {
self.name = name
self.value = value
}
}
// MARK: Header convenience initializers and mutators
extension Header {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(Header.self, from: data)
self.init(name: me.name, value: me.value)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
name: String? = nil,
value: String? = nil
) -> Header {
return Header(
name: name ?? self.name,
value: value ?? self.value
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: - Helper functions for creating encoders and decoders
func newJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
return decoder
}
func newJSONEncoder() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}
This almost works perfectly; except for the attachmentID parameter - when I try to create an email, I get this error:
keyNotFound(CodingKeys(stringValue: "attachmentId", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "payload", intValue: nil), CodingKeys(stringValue: "body", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"attachmentId\", intValue: nil) (\"attachmentId\").", underlyingError: nil))
Kind of at my whit's end on this; so any help appreciated - what do I need to do to make sure that this property will get assigned?
EDIT I forgot to include the JSON response; which is below:
{
"snippet" : "",
"id" : "1758550e1d57a61e",
"internalDate" : "1604259323000",
"sizeEstimate" : 1811162,
"threadId" : "1758549a183c08f0",
"payload" : {
"partId" : "",
"mimeType" : "video\/mp4",
"filename" : "nicholasarner#gmail.com-2020_11_01_11_35_23-WDYT?.mp4",
"body" : {
"size" : 1322930,
"attachmentId" : "ANGjdJ_nEZvNaV972a1H9osO7Ze3WH-F5hlf8cSEQjgM9NmI8XzsKsfhAF_zV7addIHsIEgm8nmlPGID8pICD5ew8399hocuXwvfGVx_Pl3Z7f1jwgmrm1_UD6k1daGkaXFFy7kbfiiRRidy42IoKT9r3FoS4tb7mVmv7ctrQE9KvCjV2Op3MCkzvrjM494iG06yJtQhM5Zt697BG-kythaCjacFJ5cTh4c-qdCN60JIUL3sR95AWnoEvSBMVr_i6iPKIP67gpddw27MkMmqICA8jkJXXSGhGaZek2hJu886ik_3VCvqlQ4c2uypWVYNOfWMPvjVuNmlW-_MH41cSo_mqd2DaxBVkXut70bu24y2-aY50ljhVZRqhV6CSoUlbBiPEe_VxToATBy_vFLF8TZRlOGg5Jq0kleymZvRgg"
},
"headers" : [
{
"name" : "Return-Path",
"value" : "<nicholasarner#gmail.com>"
},
{
"name" : "Received",
"value" : "from iPhone ([2601:645:4200:3950:441:1411:7e85:db6d]) by smtp.gmail.com with ESMTPSA id u124sm12113464pfc.21.2020.11.01.11.35.24 for <nicholasarner#gmail.com> (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128\/128); Sun, 01 Nov 2020 11:37:51 -0800 (PST)"
},
{
"name" : "Date",
"value" : "Sun, 1 Nov 2020 11:35:23 -0800"
},
{
"name" : "From",
"value" : "nicholasarner#gmail.com"
},
{
"name" : "To",
"value" : "Nick Arner <nicholasarner#gmail.com>"
},
{
"name" : "Message-ID",
"value" : "<d5ff6514-1c55-4d98-a4d3-43a776d7b05d#iPhone>"
},
{
"name" : "In-Reply-To",
"value" : "<CAD1H43XCrKQD3omFV2ggf_e2kLm_v4234p2oHvvKGd-bJ4PZeQ#mail.gmail.com>"
},
{
"name" : "Subject",
"value" : "Re: tett"
},
{
"name" : "MIME-Version",
"value" : "1.0"
},
{
"name" : "Content-Type",
"value" : "video\/mp4"
},
{
"name" : "Content-Transfer-Encoding",
"value" : "base64"
},
{
"name" : "Content-Disposition",
"value" : "attachment; filename=\"nicholasarner#gmail.com-2020_11_01_11_35_23-WDYT?.mp4\""
}
]
},
"historyId" : "11441245",
"labelIds" : [
"IMPORTANT",
"SENT",
"INBOX"
]
}
I come back with my problem and I still find no answer
according to the previous solutions I had to develop the function to retrieve information (lastname, name) on the token
func loadMemberProfil(completion: ((_ sub : [String: AnyObject]) -> Void)!) {
// get API profile and Bearer token
let token = HPWSLoginManager.shared().saveSuccessResponse.token
let url = URL(string: "http://51.38.36.76:40/api/v1/profile")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
request.addValue("Bearer \(token!)", forHTTPHeaderField: "Authorization")
//get information in token
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: AnyObject]
let sub = json["sub"] as! [String: AnyObject]
if completion != nil{
completion(sub)
}
} catch {
print("error")
}
}.resume()
}
And in this function (that I call in viewDidLoad()) I want to display the name and lastname but nothing is displayed when I run the emulator
func initTableViewModel() {
self.loadMemberProfil { (sub) in
let headerMenu = HPMenuHeaderViewModel.init(firstName: "\(sub["firstname"])", lastName: "\(sub["lastname"])")
let tableViewModel = HPMenuViewModel(titlePage: "Menu", array: arrayCellModel, headerMenuViewModel: headerMenu)
self.tableViewModel = tableViewModel
}
}
but i recover the values in the console please hep me
You are fetching but not reloading the data. You might want to read the documentation to understand the problem.
After you initTableViewModel you need to use the code below to reload the data. Note that the DispatchQueue.main.async is for doing that in the main thread.
DispatchQueue.main.async {
self.tableView.reloadData()
}
in HPMenuHeaderViewModel class
class HPMenuHeaderViewModel: NSObject {
var imageName: UIImage?
var firstName: String?
var lastName: String?
var numberString: String?
var name: String {
return String.safe(firstName) + " " + String.safe(lastName)
}
var nameInitials: String {
let arrayName = self.name.components(separatedBy: " ")
return arrayName.reduce("") { $0.safePrefix(1) + $1.safePrefix(1)}
}
#objc init(firstName: String, lastName: String, numberString: String) {
super.init()
self.firstName = firstName
self.lastName = lastName
self.numberString = numberString
}
}
in HPMenuViewModel class
class HPMenuViewModel: NSObject {
var titlePage: String?
var accountTableViewCellModel: [HPMenuTableViewCellModel]?
var headerMenuViewModel: HPMenuHeaderViewModel?
init(titlePage: String, array accountTableViewCellModel: [HPMenuTableViewCellModel]?, headerMenuViewModel: HPMenuHeaderViewModel ) {
super.init()
self.titlePage = titlePage
self.accountTableViewCellModel = accountTableViewCellModel
self.headerMenuViewModel = headerMenuViewModel
}
}
I use MVVM architecture
I'm having issues trying to access a string inside of a JSON dictionary, Here is the JSON data, the string I'm trying to access is the "link" value :
channels = (
{
social = {
facebook = {
"facebook_id" = 47360808996;
link = "https://www.facebook.com/CBS";
};
twitter = {
link = "https://twitter.com/CBS";
"twitter_id" = 97739866;
};
};
}
);
Here is the custom objects I created which keeps giving me an error
" Type '(key: String, value: AnyObject)' has no subscript members"
class SocialInfo: NSObject, Mappable {
var facebook: String?
var facebookDict: String?
required init?(map: Map) {
}
func mapping(map: Map) {
///transforms string to dictionary [string: anyobject] - only used for specific JSON data name: (facebook) - (link)
let facebookTransform = TransformOf<String, [String: AnyObject]> (fromJSON: { (value: [String: AnyObject]?) -> String? in
if let value = value {
for dict in value {
if let social = dict["social"] as? NSDictionary {
if let fb = social["facebook"] as? [String: AnyObject]{
if let fbLink = fb["link"] as? String{
return fbLink
}
}
}
}
}
return nil
}, toJSON: { (value: String?) -> [String: AnyObject]? in
return nil
})
facebookDict <- (map["channels"], facebookTransform)
facebook <- map["link"]
}
}
Here is my JSON call function to get info:
func getSocialInfo (_ completion: (([SocialInfo]) -> Void)?) {
Alamofire.request("\(baseURL)/\(apiKey)/show/950", method: .get, encoding: JSONEncoding.default).responseArray { (response: DataResponse<[SocialInfo]>) in
if let channelsResponse = response.result.value {
completion?(channelsResponse)
}
}
}
For reference I recreated this from a working project using NSURLSession the below code works:
if let channels = jsonResult["channels"] as? [[String:AnyObject]], !channels.isEmpty {
let channel = channels[0] // now the compiler knows it's [String:AnyObject]
let social = channel["social"] as? NSDictionary
let facebookDict = social!["facebook"] as? [String:AnyObject]
let facebook = nullToNil(facebookDict!["link"]) as? String ?? "N/A"
let twitterDict = social!["twitter"] as? [String:AnyObject]
let twitter = nullToNil(twitterDict!["link"]) as? String ?? "N/A"
I will assume you use Swift 3, as Swift 2 is deprecated.
You should avoid NSDictionary and AnyObject when parsing JSON in Swift 3. Simply use [String: Any] everywhere instead.
I want to parse this JSON :http://jsonplaceholder.typicode.com/users
I have a problem for find JSON structure.
I am trying JSON with this structure that is work well, but I don't sure of this is better way or is not!
what is the best way for parsing this JSON array to post instance?
there is my code:
func profileFromJSONData(data : NSData) -> ProfileResult {
do{
let jsonObject : NSArray!
= try NSJSONSerialization.JSONObjectWithData(data, options: []) as! NSArray
for profileJSON in jsonObject {
if let profile = profileFromJsonObject(profileJSON as! NSDictionary) {
finalProfile.append(profile)
}
}
return .Success(finalProfile)
}
catch let error {
return .Failure(error)
}
}
func profileFromJsonObject(json: NSDictionary) -> UserProfile?{
guard let
id = json["id"] as? Int,
name = json["name"] as? String,
userName = json["username"] as? String,
email = json["email"] as? String,
address = json["address"] as? NSDictionary,
phone = json["phone"] as? String,
website = json["website"] as? String,
company = json["company"] as? NSDictionary
else {
return nil
}
let obj = UserProfile(id: id, name: name, userName: userName, email: email, address: address, phone: phone, website: website, company: company)
return obj
}
Here is what apple suggestion when Working with JSON in Swift,
and you can improve your code to one line by using flatMap
change from:
for profileJSON in jsonObject {
if let profile = profileFromJsonObject(profileJSON) {
finalProfile.append(profile)
}
}
to:
finalProfile += jsonObject.flatMap(profileFromJsonObject)
That's the same.
Deal with address:
struct Address {
var street: String
var city: String
...
init?(json: [String: AnyObject]){...}
}
extension Address: CustomStringConvertible {
var description: String {
return "street: \(street), city: \(city)"
}
}
func profileFromJsonObject(json: [String: AnyObject]) -> UserProfile? {
guard let
...
addressJson = json["address"] as? [String: AnyObject]
address = Address(json: addressJson),
...
else {
return nil
}
let obj = UserProfile(id: id, name: name, userName: userName, email: email, address: address, phone: phone, website: website, company: company)
print(address) // output: "street: Kulas Light, city: Gwenborough"
}
I create a swift class as shown below:
class Message {
var type:String
var content:[UInt8] = [UInt8]()
init(type:String, content:[UInt8]) {
self.type = type
self.content = content
}
func jsonAsString()->String {
var dict = [String: AnyObject]()
let mirror = Mirror(reflecting: self)
for (_, attr) in mirror.children.enumerate() {
if let property_name = attr.label as String! {
print("property_name: \(property_name) and value:\(attr.value)")
dict[property_name] = attr.value as? AnyObject
}
}
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions.PrettyPrinted)
return (String(data: jsonData, encoding: NSUTF8StringEncoding)?.stringByReplacingOccurrencesOfString(" ", withString: ""))!
} catch {
NSLog("ERROR when parse JSON")
}
return ""
}
}
I want to call the function 'jsonAsString' to get a json string, but the property 'content' which is an uint8 array not convert correctly.
As I found a lot, some one suggest to replace
var dict = String: AnyObject with
var dict = String: Any
But this type of dictionary is not supported by the method
NSJSONSerialization.dataWithJSONObject(obj: AnyObject, options opt: NSJSONWritingOptions) throws -> NSData