I have a post request that has a body like this
{
"cars": [
{
"id": 126,
"drivers": [
"xxx#gmail.com"
]
},
{
"id": 128,
"drivers": [
"mmm#gmail.com"
]
}
]
}
the id and drivers are changeable, and I got them from another api so how to send this body with the post request?
on the other hand I have a textField that takes another email of driver, I want to change drivers when this request was sent.
example:
{
"cars": [
{
"id": 126,
"drivers": [
"xxx#gmail.com",
"sss#gmail.com"
]
},
{
"id": 128,
"drivers": [
"mmm#gmail.com"
]
}
]
}
As you can see I want to update the drivers to the new one when I tap add button on the specific textField depends on the id.
This is my code
public static func loadDrivers(owners: [Owner], drivers: [Driver], driverEmail: String!, i: Int, completion: #escaping (_ code:Int?)-> Void) {
let headers: HTTPHeaders = [
"Accept": "application/json"
]
var para2 = [String : [[String : Any]]]()
para2 = [
"cars": [
[
"id": owners[i].id,
"drivers": [
drivers[i].email,
driverEmail
]
]
]
]
if driverEmail != nil {
Alamofire.request(APIHelper.BASE_URL + APIHelper.API.ADD_DRIVERS.rawValue, method: .post, parameters: para2, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
switch response.result {
case .success:
let json = response.result.value as? NSDictionary
let code = json!["code"]
completion(code as? Int)
case .failure(let error):
print(error)
completion(nil)
return
}
}
}
}
Thanks in advance
This question is screaming Codable protocol at me, so here it goes. The Codable protocol makes using true Swift objects to generate JSON a real breeze. Try this in a Playground:
import Cocoa
struct Car : Codable {
let id:Int
let drivers:[String] // you will want to improve on this
}
struct Mobiles : Codable {
let cars:[Car]
}
var mobiles = Mobiles(cars:[Car(id:126, drivers:["xxx#gmail.com", "sss#gmail.com"]),
Car(id:128, drivers:["mmm#gmail.com"])])
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
print(String(data:try encoder.encode(mobiles), encoding:.utf8)!)
Since you should be able to employ Swift on both ends of this equation it is easy to see that this requires a lot less code than your example.
As you said in the Json example you have a array of dictionaries in 'Cars' field but you are making a dictionary inside a dictionary in this line:
var para2 = [String : [[String : Any]]]()
You can define your para2 in this way:
var para2 = [String, Array<[String:Any]>]
and then send it as a parameters
Related
I'm having trouble trying to figure out how to return only one part of my JSON data using Swift 4.
This is the JSON I need to parse:
{
"code": 0,
"responseTS": 1571969400172,
"message": "TagPosition",
"version": "2.1",
"command": "http://123.456.7.89:8080/tag=a4da22e02925",
"tags": [
{
"smoothedPosition": [
-0.58,
-3.57,
0.2
],
"color": "#FF0000",
"positionAccuracy": 0.07,
"smoothedPositionAccuracy": 0.07,
"zones": [],
"coordinateSystemId": "687eba45-7af4-4b7d-96ed-df709ec1ced1",
"areaId": "987537ae-42f3-4bb5-8d0c-79fba8752ef4",
"coordinateSystemName": "CoordSys001",
"covarianceMatrix": [
0.04,
0.01,
0.01,
0.05
],
"areaName": "area",
"name": null,
"positionTS": 1571969399065,
"id": "a4da22e02925",
"position": [
-0.58,
-3.57,
0.2
]
}
],
"status": "Ok"
}
So far I am able to return all of the "tags" array, shown below. However, I just need to return only the "smoothedPosition" data.
func newTest() {
Alamofire.request(url).responseJSON { (response) in
if let newjson = response.result.value as! [String: Any]? {
print(newjson["tags"] as! NSArray)
}
}
}
Would alamofire be a good way to get the result I want? I previously tried with the Codable method but because there are many different parts to my JSON, I found it confusing to just get the part I need. If anyone could give me some advice on the best way to go about this, I would appreciate it.
Better not to use NS classes with Swift wherever possible. So instead of NSArray use Array.
To get smoothedPosition you need to parse more. tags gives you an array of dictionaries, so you need to loop array and get each dictionary inside tags array. Then finally you can get your smoothedPosition array.
func newTest() {
Alamofire.request(url).responseJSON { (response) in
if let newjson = response.result.value as? [String: Any], if let tagArray = newjson["tags"] as? [[String: Any]] {
for object in tagArray {
if let smoothedPosition = object["smoothedPosition"] as? [Double] {
print(smoothedPosition)
}
}
}
}
}
Also you should read more about codables to parse nested data and learn about optional binding and chaining to prevent crashes when you force (!) something which could be nil at some point.
You can use this site to check the possible Codable structure as per your response: https://app.quicktype.io/
It is a good option to create a custom Codable struct or class for the JSON response. You may only implement as member variable which you want to reach.
struct CustomResponse: Codable {
let tags: [Tag]
}
struct Tag: Codable {
let smoothedPosition: Position
}
struct Position: Codable {
let x: Float
let y: Float
let z: Float
}
Then
Alamofire.request(url).responseJSON { (response as? CustomResponse) in
guard let response = response else { return }
print(response.tags.smoothedPosition)
}
Also you can parse deeper manually your JSON response as stated in the other answers.
I am new in swift and I am also trying to use Alamofire to call data from API. I am quite puzzled on how I will use the PUT Request to update data. I've read some solutions here in SO but I don't know how I will apply on my app. I am creating an Event App, the scenario should be, when the participant clicked the Check In Button, it will update the registered_flag to true meaning the participant will marked as Registered and the button will be changed to Check Out. I really don't know if my API Service is correct or not. Hope you could help me. Thank you so much.
JSON of the Event Participant Where in the registered_flag should be updated once checkInOutButton
{
"event_name": "Q & A",
"event_participants": [
{
"participant_id": "70984656-92bc-4c36-9314-2c741f068523",
"employee_number": null,
"last_name": "Surname",
"first_name": "FirstName",
"middle_name": null,
"display_name": "Surname, FirstName ",
"department_name": "Medical Informatics",
"position_name": "Application Developer",
"registered_flag": true,
"registered_datetime": "2018-09-13T08:54:40.150",
"registration_type": 1,
"delete_flag": false,
"manual_reg_flag": false,
"out_flag": false,
"out_datetime": null,
"classification": 6,
"others": "Guest"
}
}
JSON to update for check in
{
"registered_flag": true,
"registration_type": 1
}
updateType
enum UpdateParticipantType: String {
case checkIn = "Check In"
case checkOut = "Check Out"
}
APIService for UpdateParticipant
func updateParticipant(updateType: UpdateParticipantType,
participantID: String,
successBlock: #escaping ([Attendee]) -> Void,
failureBlock: #escaping (Error) -> Void)
{
let updateParticipantURL = URL(string: "\(REGISTER_PARTICIPANT_URL)/\(updateType)/\(participantID)")
Alamofire.request(updateParticipantURL!, method: .put).responseJSON { (response) in
print(response)
if let error = response.error
{
failureBlock(error)
print(error)
return
}
if let jsonArray = response.result.value as? [[String : Any]] {
for anItem in jsonArray {
if let eventparticipants = anItem["event_participants"] as? [[String : Any]] {
var extractedAttendees = [Attendee]()
for participants in eventparticipants{
let success = Attendee.init(JSON: participants)
extractedAttendees.append(success!)
}
successBlock(extractedAttendees)
}
}
}
}
}
As per Alamofire documentation:
let parameters: Parameters = [
"foo": "bar",
"baz": ["a", 1],
"qux": [
"x": 1,
"y": 2,
"z": 3
]
]
Alamofire.request("https://httpbin.org/post", method: .post, parameters: parameters)
For a given json
{
"registered_flag": true,
"registration_type": 1
}
let parameters: Parameters = [
"registered_flag": true
"registration_type": 1
]
On click of a submit button the data in my textfields and some other data are being converted to a json object like so…
let categoryName = self.categoryTextField.text
let categoryId = self.categoryID
let category_json: [String: [String:Any]] = [
"categoryDetails": [
"category_name": categoryName,
"category_id": categoryId
]
]
if let data = try? JSONSerialization.data(withJSONObject: category_json, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) // `str` gives the json object
self.categoryStrToPass = str
}
Now self.categoryStrToPass is assigned to another json object and then finally added to a string array like so…
let productID = self.prodID
let sellingPrice = self.mrpTextField.text
let categoryJSON = self.categoryStrToPass
let jsonObject: [String: [String:Any]] = [
"prodDetails": [
"product_id": productID,
"selling_price": sellingPrice,
“category_json”: categoryJSON
]
]
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str)
self.jsonStrToPass = str
self.jsonStringArray.append(self.jsonStrToPass)
}
Now I’m storing jsonStringArray to coredata like so…
_product?.setValue(self.jsonStringArray, forKey:
"productJsonArray") // productJsonArray is an attribute of type Transformable and Custom class type Array<String>
And it is being fetched like so...
if let jsonObjArr = result.value(forKey: "productJsonArray") as?
Array<NSString> {
print(jsonObjArr)
}
Now on 2 different instances I have submitted the data which means on printing jsonObjArr while fetching,it should have 2 different json objects in one array like so..
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}
{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
But instead, printing jsonObjArr is giving this…in 2 different arrays like so...
[{
"prodDetails" : {
"product_id" : "0",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"prodCAT\"\n }\n}",
"selling_price" : "500",
}
}]
[{
"prodDetails" : {
"product_id" : "1",
"category_json" : "{\n \"categoryDetails\" : {\n \"category_id\" : \"0\",\n \"category_name\" : \"CATNEW\"\n }\n}",
"selling_price" : "1000",
}
}]
How can I get multiple json objects in one single array...?
you can add objects of type [String: Any] to array like so
let firstCategoryName = "first"
let firstCategoryId = 1
let firstCategory = [
"category_name": firstCategoryName,
"category_id": firstCategoryId
] as [String : Any]
let secondCategoryName = "second"
let secondCategoryId = 2
var category_json = [[String:Any]]()
category_json.append(firstCategory)
let secondCategory = [
"category_name": secondCategoryName,
"category_id": secondCategoryId
] as [String : Any]
category_json.append(secondCategory)
print(category_json)
then serialize the array
Swift 4.0:
let firstObj = ["prodDetails": [
"product_id": 5,
"selling_price": 6,
]]
let secondObj = ["prodDetails1": [
"product_id1": 5,
"selling_price1": 6,
]]
let jsonObject = jsonStringArray.addingObjects(from: [firstObj,secondObj])
if let data = try? JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted),
let str = String(data: data, encoding: .utf8) {
print(str) //prints array of dictionaries
}
category_json and jsonObject are of the same kind.
What you need to understand:
(NS)String <== String(data:encoding) or data(encoding:) ==> (NS)Data
Applied to specific String/Data: JSON:
JSON Stringified <== String(data:encoding) or data(encoding:) ==> JSON Data
Swift Array/ Swift (and the rest JSON compliant) <== (NS)JSONSerialization.jsonObject(withData:, options:) or (NS)JSONSerialization.data(withJSONObject:, options:) ==> JSON Data
You can't append like that the two JSON Stringified, you need to have an array at least at top level.
So, let's connect the dots, in pseudo code (not sure at all that the method name are error free)
let currentData = self.jsonStrToPass.data(encoding: .utf8)
let current = JSONSerialization.jsonObject(with:currentData, options:[]) as [String:[String:Any]]
let finalArray : [[String:[String:Any]]]()
finalArray.append(current)
finalArray.append(jsonObject)
let finalData = JSONSerialization.data(withJSONObject:finalArray, options:[])
let finalString = String(data:finalData, encoding:.utf8)
That's for the logic. I didn't do the if let, try/catch, etc.
I'd think it might be better to pass Any (for Swift Array/Dictionary instead of String) between your data to pass. It might be simpler to edit them (append, etc.) instead of String.
How would I proceed to map a realm result to a JSON format.
Here are my Realm object classes.
class OrderItemList: Object {
dynamic var dateCreated = NSDate()
let orderItems = List<OrderItem>()
}
class OrderItem: Object {
dynamic var name = " "
dynamic var amount = 0
dynamic var internalUnique = Int()
dynamic var isCompleted = false
}
I want to map the result of the data saved and send it to an API like so:
let orderRequestUserValues = [ "ClientID": "TEST",
"UserName": "sysadmin",
"Password": "123456",
"ModuleID": "StockProcessing",
"FunctionID": "SetStockOrder",
"TransmissionFlags": 32,
"TransmissionMethod": 5,
"RequestParameters":
[
"OrderType": 1,
"Notes": "John Is Reordering",
"ListofStockItemOrderData": //Here is where the mapped JSON will be
]
]
Via Alamofire:
manager.request(.POST, url, parameters: orderRequestUserValues)
You can add the following function to your OrderItemList to convert its orderItems List to a JSON string:
func orderItemsJSON() throws -> String? {
let serializableOrderItems = Array(orderItems.map({ item in
return [
"name": item.name,
"amount": item.amount,
"internalUnique": item.internalUnique,
"isCompleted": item.isCompleted
]
}))
let jsonData = try JSONSerialization.data(withJSONObject: serializableOrderItems, options: .prettyPrinted)
return String(data: jsonData, encoding: .utf8)
}
I am very new to programming, let alone Swift. I understand some concepts from previous attempts at programming so I have gotten further than ever before. I apologize if I am not clear in what I need.
I am pulling in JSON data of a list of alerts and I am trying to parse the data with swiftyJSON which I think is working out ok but I have run into a snag of trying to grab some data from some dictionaries within an array, and unfortunately inside a dictionary inside this arrary is where the email address is, and the different dictionaries use similar keys within each other.
I am going to show you my struct, fucntion and JSON data. Please help me grab the email address, service - its ID and its label. Also, there may be more than one Service as in the data shown and I need to capture all of them.
HERE IS THE JSON DATA:
{
"hasNext": false,
"data": [
{
"status": [
1,
"READ"
],
"resolutionStatus": [
0,
"OPEN"
],
"description": "There is some description here",
"title": "Some Activity",
"entities": [
{
"view_name": "audits",
"type": "link",
"parameters": {
"orgUnit": "/"
},
"label": "/"
},
{
"type": "user",
"id": "hidden#hidden.com",
"label": "hidden#hidden.com"
},
{
"type": "service",
"id": 6666,
"label": "someService"
},
{
"type": "service",
"id": 7777,
"label": "anotherService"
}
],
"stories": [
5
],
"date": "2014-12-10T23:46:28.067000Z",
"audits": [
"ljBhqKQVOF9w",
"pISQyT9iy9w",
"oynGf2_CIw"
],
"_id": "54fdad0dfd",
"id": [
14683,
"ALERT_SOME_ACTIVITY"
],
"severity": [
5,
"HIGH"
]
}
Here is my Struct:
struct AlertModel: Printable {
let alertUser: String?
let alertService: String?
let alertTitle: String?
let alertReadStatus: String?
let alertResolutionStatus: String?
let alertDescription: String?
let alertEntities: Array <String> = []
let alertDate: String?
let alertAudits: Array <String> = []
let alertId: String?
let
alertSeverity: String?
// change description to print to console
var description: String {
return "User: \(alertUser)\nService: \(alertService)\nTitle: \(alertTitle!)\nRead Status: \(alertReadStatus!)\nResolution Status: \(alertResolutionStatus!)\nDescription: \(alertDescription!)\nDate: \(alertDate!)\nAlert ID: \(alertId!)\nSeverity: \(alertSeverity!)\n******************************************\n"
}
init(alertUser: String?, alertService: String?, alertTitle: String?, alertReadStat
us: String?, alertResolutionStatus: String?, alertDescription: String?/*, alertEntities: Array<String>*/, alertDate: String?/*, alertAudits: Array<String>*/, alertId: String?, alertSeverity: String?) {
self.alertUser = alertUser
self.alertService = alertService
self.alertTitle = alertTitle
self.alertReadStatus = alertReadStatus
self.alertResolutionStatus = alertResolutionStatus
self.alertDescription = alertDescription
//self.alertEntities = alertEntities
self.alertDate = alertDate
//self.alertAudits = alertAudits
self.alertId = alertId
self.alertSeverity = alertSeverity
}
AND HERE IS THE FUNCTION:
let jsonAlert = JSON(data: jsonAlertObject)
if let alertArray = jsonAlert["data"].array {
var alerts = [AlertModel]()
for alertDict in alertArray {
let alertTitle: String? = alertDict["title"].stringValue
let alertReadStatus: String? = alertDict["status"][1].stringValue
let alertResolutionStatus: String? = alertDict["resolutionStatus"][1].stringValue
let alertDescription: String? = alertDict["description"].stringValue
let alertDate: String? = alertDict["date"].stringValue
let alertId: String? = alertDict["_id"].stringValue
// Need to grab the type and label from each dictionary in the array of entities
let alertEntitiesArray: Array? = alertDict["entities"].arrayObject
var arrayIndex = 0
var entitiesDict = ["" : ""]
while arrayIndex < alertEntitiesArray?.count {
entitiesDict[alertDict["entities"][arrayIndex]["type"].stringValue] = alertDict["entities"][arrayIndex]["label"].stringValue
arrayIndex++
}
let alertService: String? = entitiesDict["service"]
let alertUser: String? = entitiesDict["user"]
let alertSeverity: String? = alertDict["severity"][1].stringValue
let alert = AlertModel(alertUser: alertUser, alertService: alertService, alertTitle: alertTitle, alertReadStatus: alertReadStatus, alertResolutionStatus: alertResolutionStatus, alertDescription: alertDescription, alertDate: alertDate, alertId: alertId, alertSeverity: alertSeverity)
alerts.append(alert)
var alertsDictionaryByID = [alertId!: alert]
}
println(alerts)
}
As you can see the JSON data is a few levels deep. I have no problem getting to the data and pulling it out. The problem is the "Entities" array may not always have the same data in it. It my have multiple services, it may have no email address, it may have a completely different set of data for the first value of the array.
I am trying to get the email address out. If I could find a way to search for the "user" as with the dictionary data and then when found it would return the array index value to be able to reference it directly because I will never know with index number the user value is part of.
I hope I came across clear enough and someone can help me. --- my next step will be populating a listView with each individual alert.
I was also using SwiftyJSON, but using NSURLConnection was easy. Like this method.
//MARK: - NSURLConnection Delegate methods
var responseData : NSMutableData = NSMutableData()
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!)
{
self.responseData.length = 0
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!)
{
self.responseData.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!)
{
if let responseDatas = responseData as NSData? {
if let jsonResult : NSDictionary = NSJSONSerialization.JSONObjectWithData(responseDatas, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary? {
if let dataArray = jsonResult.valueForKeyPath("data") as? NSArray
{
if let entitiesArray = dataArray.valueForKeyPath("entities") as? NSArray
{
if let firstArray = dataArray[0]
{
// access your viewName and types here
}
// Like this method, convert all your parameters and access it.
}
}
else
{
// Do something here
}
}
else
{
// Do something here
}
}
else
{
// Do something here
}
}
func connection(connection: NSURLConnection!, didFailWithError error: NSError!)
{
// Do something here
}
I ended up finding SwiftyJSON and Alamofire to significantly assist with the networking and JSON Serialization.
As far as my issue with the dictionaries within the array I ended up creating a function that iterated through the entities array looking at each dictionary seperately and then performed a Switch statement based on the key="type" to determine if it was the "user" dictionary or the "service" dictionary and then combined the 'type' value, which said if it was a user or a service, with the value of "label", which is the the username or service name, and created a new dictionary out of that which I could then reference to put back into my data model.
class func retrieveDataFromEntitiesArray (alertDict: JSON) -> (entitesDict: Dictionary<String, String>, servicesArray: [String]) {
// Need to create an array object, instead of a JSON object, of the entities array to be able to get a count to run the while against.
var arrayIndex = 0
var entitiesDict: Dictionary<String, String> = [:]
var alertEntitiesArray = alertDict.arrayObject
var servicesArray = [String]()
while arrayIndex < alertEntitiesArray?.count {
var dictKey = alertDict[arrayIndex]["type"].string
switch (dictKey!) {
case "user":
entitiesDict[alertDict[arrayIndex]["type"].stringValue] = alertDict[arrayIndex]["label"].stringValue
case "service":
servicesArray.append(alertDict[arrayIndex]["label"].stringValue)
case "policyRule":
entitiesDict[alertDict[arrayIndex]["type"].stringValue] = alertDict[arrayIndex]["label"].stringValue
default:
println("Nothing Here")
}
arrayIndex++
}
return (entitiesDict, servicesArray)
}