So, I'm download data from an API using SwiftyJSON. I'm converting it, and looping through to get all of the results. I'm trying to get a specific part of each result to print out, but I can't seem to get it working.
The code I'm using below takes the json, and loops through it and prints out what is also below. From what is printed, I just want to get the "subject".
do {
let jsonObj = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
let json = JSON(jsonObj)
let pms: NSArray = json["result"]["pms"].arrayValue as NSArray
let arrayLength = pms.count
for var i in (0..<arrayLength) {
let pm = pms[i]
i+=1
}
} catch let error as NSError {
print(error)
}
Which then gives values like:
{
"subject" : "Example",
"status" : 1,
"recipient" : 012345,
"recipientusername" : "Example",
"dateline" : "2018-01-01",
"sender" : 012345,
"pmid" : 012345,
"senderusername" : "DoctorSheep"
}
{
"subject" : "Example 2",
"status" : 1,
"recipient" : 678910,
"recipientusername" : "Example 2",
"dateline" : "2018-01-01",
"sender" : 678910,
"pmid" : 678910,
"senderusername" : "Example 2"
}
If I try something like
let subject = pm["subject"]
I get an error that "Type 'Any' has no subscript members".
let pms = json["result"]["pms"].arrayValue as Array
let arrayLength = pms.count
for var i in (0..<arrayLength) {
let pm = pms[i]
let subject = pm["subject"]
print(subject)
i+=1
}
Related
JSON file:
[
{
"name" : "Tom Harrys",
"email" : "tommyHarrys#abc.com",
"password" : "tomharry123"
},
{
"name" : "Sam Billing",
"email" : "samybilling#abc.com",
"password" : "sambillings789"
},
{
"name" : "Adam Gosh",
"email" : "adagoshy#abc.com",
"password" : "adamghosy989"
}
]
UTIL file:
class Utils {
static func loadData(filename : String) -> [Any] {
let filePath = Bundle(for: self).path(forResource: filename, ofType: "json") ?? "default"
let url = URL(fileURLWithPath: filePath)
do {
let data = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
let exampleArray = json as! [Any]
if exampleArray.isEmpty {
XCTFail("Source file \(filename) is empty.")
}
return exampleArray
}
catch {
XCTFail("Error: \(error)")
XCTFail("File \(filename) not found.")
return []
}
}
}
Test file:
func loginAccount() {
let dataSource = Utils.loadData(filename: "example")
dataSource.contains(where: { ($0.name == "Sam Billing"})
}
In this code dataSource got 3 value same as Json file.
Now I want to fill the sign up form with specific value
( "name" : "Sam Billing",
"email" : "samybilling#abc.com",
"password" : "sambillings789"
)
from the array.
You should not be using JSONSerializer in Swift. A better option is a JSONDecoder. JSONDecoder will allow you to establish and preserve the type information for the data you've decoded. Here is an Playground example of how you would use JSONDecoder to handle this data set, then one technique extract Sam's record from the array of users.
import UIKit
import Foundation
let JSONContent = """
[
{
"name" : "Tom Harrys",
"email" : "tommyHarrys#abc.com",
"password" : "tomharry123"
},
{
"name" : "Sam Billing",
"email" : "samybilling#abc.com",
"password" : "sambillings789"
},
{
"name" : "Adam Gosh",
"email" : "adagoshy#abc.com",
"password" : "adamghosy989"
}
]
""".data(using: .utf8)!
struct UserRecord : Decodable {
let name : String
let email: String
let password: String // Don't pass passwords in plain text around in JSON
}
class Utils {
static func loadData() -> [UserRecord] {
do {
let decoder = JSONDecoder()
let data = JSONContent
let json = try decoder.decode([UserRecord].self, from: data)
return json
}
catch let error {
print("The json could not be decoded \(error)")
return []
}
}
}
let users = Utils.loadData()
if let sam = users.first(where: { user in user.email.caseInsensitiveCompare("samybilling#abc.com") == .orderedSame }) {
debugPrint(sam)
} else {
print("Sam was missing")
}
I want to send array object to web service, but when I try to add array to parameters it gives error. I tried many things but nothing found usefully.
I want to add ("assignees" : newList) in parameter and than send it to web service
Here is my code
var newList = [Assignee]()
var assignee = Assignee()
for u in task.NewWorkList! {
assignee = Assignee()
assignee.assignedEmail = u.Email
assignee.assignedName = u.Name
assignee.assignedSurname = u.Surname
assignee.assignedType = "PERSONEL"
assignee.assignedTo = String(u.Id!)
newList.append(assignee)
}
// in this part newList is an array of assignees.
var assigneeListString = ""
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(newList)
assigneeListString = String(data: jsonData, encoding: .utf8)!
print("assigneeListString:",assigneeListString)
} catch {
print("error:::")
}
var parameters = [
"taskType" :
[
"code" : "OTHER"
],
"complateButtons": "COMPLATE",
"assignees" : [JSON(assigneeListString)], // does not work
// "assignees" : [JSON(newList)], // does not work
// "assignees" : JSON(newList), // does not work
// "assignees" : newList, // does not work
// "assignees" : assigneeListString, // does not work
"repeatTimeType":"NEVER"
] as [String : Any]
print("parameters:",parameters)
DAL.Service.MakeRequest(url: Constants.Service.Url.newTask,
parameters : parameters,
httpMethod : ServiceMethods.post.rawValue,
resultFunc: serviceResultFunc)
when I print parameters assignee section adds extra semi colon,
[[{"assignedTo":"63659","assignedSurname":"DAVID","assignedType":"PERSONEL","assignedName":"JOE","assignedEmail":"joe#abc.com"},{"assignedTo":"21026","assignedSurname":"GEORGE","assignedType":"PERSONEL","assignedName":"MICHAEL","assignedEmail":"michael#abc.com"}]],
when I manually add assignees to patameters , its ok.
[["assignedTo":"63659","assignedSurname":"DAVID","assignedType":"PERSONEL","assignedName":"JOE","assignedEmail":"joe#abc.com"},{"assignedTo":"21026","assignedSurname":"GEORGE","assignedType":"PERSONEL","assignedName":"MICHAEL","assignedEmail":"michael#abc.com"]],
I solved the problem with below code:
var assigneesList = [[String:Any]]()
for a in task.YeniGorevAtamaList! {
assigneesList.append(
["assignedTo":(a.Id) ?? "0",
"assignedSurname":a.Surname ?? "",
"assignedType":a.assignedType ?? "PERSONEL",
"assignedName":a.Name ?? "",
"assignedEmail":a.Email as Any
]
);
}
let parameters = [
"taskType" :
[
"code" : "DIGER"
],
"assignees" : assigneesList ,
"taskUrls" :
[
]
] as [String : Any]
i have some question and solution, i have class model and it has array inside, my model like this
class WillModel{
var name: String = ""
var documents:[WillItems] = []
var isLFStatus : Bool = false
var isLFShared : Bool = false
}
class WillItems{
var documentPath: String = ""
var documentRemark: String = ""
}
i want to convert the result to JSON Array like
{
"name" : "value",
"documents" : [
{
"documentPath" : "value"
"documentRemark" : "value"
},
{
"documentPath" : "value2"
"documentRemark" : "value2"
}
],
"isLFStatus" : true,
"isLFShared" : true
}
i'm using Swift 3, thanks for your solutions
You can write a simple method to manually encode your model to json as below,
func encodeWillModel(_ model: WillModel) -> [String: Any] {
var params: [String: Any] = [:]
params["name"] = model.name
params["documents"] = model.documents.map({["documentPath": $0.documentPath,
"documentRemark": $0.documentRemark]})
params["isLFStatus"] = model.isLFStatus
params["isLFShared"] = model.isLFShared
return params
}
and you can pass any model to get the json something like,
let willModelJSON = encodeWillModel(yourModel)
But a better approach would be to use any json parsing library(SwiftyJSON, ObjectMapper) that supports Swift 3 or upgrade to Swift 4 and use Encodable/Decodable
I got this code:
let arrData = [["id": "1",
"name": "Apple",
"category": "Fruit"],
["id": "2",
"name": "Pie",
"category": "Fruit"],
["id": "3",
"name": "Tomato",
"category": "Vegetable"]]
let categorieNames = Array(Set(arrData.map({$0["category"]!})))
var arrResult:[[String]] = []
for i in 0..<categorieNames.count {
let categories = arrData.filter({$0["category"] == categorieNames[i]}).map({$0["name"]!})
arrResult.append(categories)
}
print("result : \(arrResult)")
it works perfectly with an Array.
But now I get my data from a json:
[{"id":"1",
"name":"Apple",
"category":"Fruits"},
{"id":"2",
"name":"Pie",
"category":"Fruits"},
{"id":"3",
"name":"Tomato",
"category":"Vegetable"}]
here is my struct and my decode function:
struct MarketStruct : Decodable {
let id : Int?
let name : String?
let category : String?
}
class MarketsCollectionViewController: UICollectionViewController, NetworkDelegate {
var myMarkets : [MarketStruct]?
var categorieNames : [Any] = []
var categorieArray:[[String]] = []
func didFinish(result: Data) {
do {
self.myMarkets = try JSONDecoder().decode([MarketStruct].self, from: result)
categorieNames = Array(Set(myMarkets!.map({ ["category": $0] })))
for i in 0..<categorieNames.count {
let categories = myMarkets!.filter({$0["category"] == categorieNames[i]}).map({["name": $0]!})
categorieArray.append(categories)
}
} catch let jsonErr {
print("Error:", jsonErr)
}
self.myCollectionView.reloadData()
}
I got an error at the filter part:
Type 'MarketStruct' has no subscript members
what must I change that the above Array code works with my JSON array?
thanks for your help.
edit my current code:
self.myMarkets = try JSONDecoder().decode([MarketStruct].self, from: result)
categorieNames = Array(Set(myMarkets.map({$0.category })))
for i in 0..<categorieNames.count {
let categories = myMarkets!.filter({$0.category == categorieNames[i]}).map({$0.name})
categorieArray.append(categories as! [String])
}
} catch let jsonErr {
print("Error:", jsonErr)
}
self.myCollectionView.reloadData()
it compiles with error: Command failed due to signal: Segmentation fault: 11
if I comment categorieNames = Array(Set(myMarkets.map({$0.category }))) out it compiles without errors
You are getting the compiler error because the category property is optional and therefore does not conform to Hashable.
Set requires that all elements conform to that.
One way to get around that is to use flatMap instead of map, which has the added capability of filtering out the nil values.
categorieNames = Array(Set(myMarkets.flatMap({$0.category })))
There are a lot of issues in the code
In the JSON the type of id is String not Int
The members in the struct are supposed to be non-optional.
The categorieNames array is supposed to be specific [String], not unspecified [Any]
In the filter line access the category by dot notation, not key subscription (Error 1)
Rather than declaring myMarkets as optional, initialize it as an empty array (Error 2)
Don't use ugly index-based for loop, use fast enumeration (not really an issue)
And why do you map myMarkets to an array of dictionaries?
struct MarketStruct : Decodable {
let id : String
let name : String
let category : String
}
var myMarkets = [MarketStruct]()
var categorieNames = [String]()
var categorieArray = [[String]]()
let jsonString = """
[{"id":"1", "name":"Apple", "category":"Fruits"},
{"id":"2", "name":"Pie", "category":"Fruits"},
{"id":"3", "name":"Tomato", "category":"Vegetable"}]
"""
let data = Data(jsonString.utf8)
do {
myMarkets = try JSONDecoder().decode([MarketStruct].self, from: data)
let categorieNames = Array(Set(myMarkets.map { $0.category }))
for categoryName in categorieNames {
let categories = myMarkets.filter({$0.category == categoryName}).map({$0.name})
categorieArray.append(categories)
}
print(categorieArray)
} catch { print(error) }
In Swift, I defined my var as:
var data : [[[String : Any]]] = [[[:]]]
then init it:
for section in 0...1 {
for row in 0...19 {
let streamer = [
"name" : "abcdef"
]
data[section][row] = streamer
}
}
but I'm gettingfatal error: Index out of range. for index data[0][1], but there's not an error for index data[0][0].
Do anybody know why I'm getting this error?
I see the problem, for some reason I was thinking swift would auto insert a section and row when I access them by subscript, but it seems that's not the case, so I changed my init to:
for sectionIndex in 0...1 {
var section : [[String : Any]] = [[:]]
for rowIndex in 0...19 {
let streamer = [
"name" : "abcdef"
]
section.insert(streamer, at: rowIndex)
}
data.insert(section, at: sectionIndex)
}