REST API: Cannot populate Tableview - ios

I am trying to pull data from an api to populate my table but nothing is being shown. How can I fix it?
UPDATED
When I place the GET request in either viewDidLoad() or viewDidAppear() I would receive an empty array
result of GET is []
I have tried adding self.tableView.reload() to the viewDidLoad() but would be thrown this error
Ambiguous reference to member 'tableView(_:numberOfRowsInSection:)'
This is my JSON response
[
{
"schedule_job_id": 23,
"start_date": "2016-05-01",
"end_date": "2016-05-08",
"building_id": 2,
"building_name": "Republic Plaza",
"building_block_no": "69A",
"building_street_name": "9 Raffles Place Downtown Core",
"building_postal_code": "233645",
"checklist_id": "1",
"checklist_name": "Lightning protection",
"checklist_due_date": "2016-04-12 17:00:00",
"tasks": [
{
"submission_id": 105,
"task_id": "1",
"task_name": "Inspect Carpark",
"task_checked": true,
"task_submitted_date": "2016-05-04 04:39:01",
"task_comment": null,
"task_building_level": "1",
"task_description": "",
"task_status": "OK",
"total_rating": null,
"safety_ratings": [
{
"submission_id": 105,
"safety_rating_id": 79,
"task_id": "1",
"name": "Equipment",
"points": "10",
"score": "0"
}
],
"photos": []
}
]
This is my GET request
override func viewDidLoad() {
usernameLabel.text = Data.sharedInstance.userName
let url = "http://anyapi.com"
Alamofire.request(.GET, url).validate().responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
if let data = json["task_name"].arrayValue as [JSON]?{
self.datas = data
self.displayTask.reloadData()
print("result of GET is \(self.datas)")
}
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
}
The entire tableview code can be seen here https://codeshare.io/aKknb

Seems like json["task_name"] is not an array and isn't at first level, instead is a property of the objects in the tasks array, thats why you are getting an empty array.
You should do something like this if you intent to show the taks in your tableview
if let data = json["tasks"].arrayValue as [JSON]?{

Because the code which makes your HTTP request is in the wrong method. You intended it to be in viewDidLoad(), but you actually put it in didReceiveMemoryWarning()

Instead of putting the population in viewDidLoad try it in viewDidAppear... that way the tableview is all setup and able to correctly populate.

you can start HTTP request in ViewWillAppear and reload the tableview.That way tableview gets properly loaded.

Related

How to fetch nested data from Firebase realtime database by implementing observer in swift

Firebase data-structure
lastLocations ( batteryStatus, lat, long, timestamp, uid)
profiles (name, phoneNumber, picture, uid)
userFriends ( basis on the uid -> how many friends -> conversationUid, friendStatus, notify, phoneNumber, uid)
My Code:
I have already created tableview and xib for it.
I have created model for last location, profiles, userFriends.
I already fetched the friend list but on Observe .ChildAdded
My uid zzV6DQSXUyUkPHgENDbZ9EjXVBj2
Link: https://drive.google.com/file/d/19cnkY03MXjrTFgzzPCdvmOuosDRvoMx9/view?usp=sharing
Issues:
Not getting an idea how to fetch location & profile with friend list efficient way with observer so any change come it reflects. Firebase is asyncrohonous process.
observer implementation so data not completely load every-time
Results to achieve:
I need to show friends list ( name, profile picture, battery status, lat long(address), timeStamp ) on tableview on the basis of my uid.
Firebase JSON
{
"lastLocations": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"batteryStatus": 22,
"latitude": 40.9910537,
"longitude": 29.020425,
"timeStamp": 1556568633477,
"uid": "FTgzbZ9uWBTkiZK9kqLZaAIhEDv1"
},
"zzV6DQSXUyUkPHgENDbZ9EjXVBj2": {
"batteryStatus": 88,
"latitude": 41.0173995,
"longitude": 29.1406086,
"timeStamp": 1571778174360,
"uid": "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
}
},
"profiles": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"fcmToken": "fp09-Y9ZAkQ:APA91bFgGB1phr4B9gZScnz7ngpqTb5MchgWRFjHmLCVmWGMJVsyFx0rtrz7roxzpE_MmuSaMc4is-XIu7j718qjRVCSHY4PvbNjL1LZ-iytaeDP0oa8aJgE02wET3cXqKviIRMH",
"name": "Skander",
"phoneNumber": "+95644125503",
"uid": "FTgzbZ9uWBTkiZK9kqLZaAIhEDv1"
},
"zzV6DQSXUyUkPHgENDbZ9EjXVBj2": {
"fcmToken": "enMneewiGgg:APA91bHyA4HypWUYhxGTUTTch8ZJ_6UUWhEIXRokmR-Y-MalwnrtV_zMsJ9p-sU_ZT4pVIvkmtJaCo7LFJYJ9ggfhc1f2HLcN9AoIevEBUqyoMN-HDzkweiUxAbyc84XSQPx7RZ1Xv",
"name": "Murad",
"phoneNumber": "+915377588674",
"picture": "profile/zzV6DQSXUyUkPHgENDbZ9EjXVBj2/a995c7f3-720f-45bf-ac58-b2df934e3dff.jpeg",
"uid": "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
}
},
"userFriends": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"zzV6DQSXUyUkPHgENDbZ9EjXVBj2": {
"conversationUid": "-L_w2yi8gh49GppDP3r5",
"friendStatus": "STATUS_ACCEPTED",
"notify": true,
"phoneNumber": "+915377588674",
"uid": "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
}
},
"zzV6DQSXUyUkPHgENDbZ9EjXVBj2": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"conversationUid": "-L_w2yi8gh49GppDP3r5",
"friendStatus": "STATUS_ACCEPTED",
"notify": true,
"phoneNumber": "+915644125503",
"uid": "FTgzbZ9uWBTkiZK9kqLZaAIhEDv1"
}
}
}
}
Swift Function:
func getFrndDataList(){
AppData.removeAll()
ref.child("userFriends").child("zzV6DQSXUyUkPHgENDbZ9EjXVBj2").observe(.childAdded, with: { (snapshot) in
guard let data = try? JSONSerialization.data(withJSONObject: snapshot.value as Any) else { return }
let frndList = try? JSONDecoder().decode(Friend.self, from: data)
self.AppData.append(frndList!)
self.tableView.reloadData()
print([frndList])
})
}
Note: After writing this answer I realized it was way long but this is a big question and there are a lot of elements to address.
My first suggestion is to change the structure as it's overly complicated for what's being done with the data. Also, there is repetitive data that's not needed so that should be changed as well. For example, here's your profiles node
"profiles": {
"FTgzbZ9uWBTkiZK9kqLZaAIhEDv1": {
"fcmToken": "fp09-Y9ZAkQ:APA91bFgGB1phr4B9gZScnz7ngpqTb5MchgWRFjHmLCVmWGMJVsyFx0rtrz7roxzpE_MmuSaMc4is-XIu7j718qjRVCSHY4PvbNjL1LZ-iytaeDP0oa8aJgE02wET3cXqKviIRMH",
"name": "Skander",
"phoneNumber": "+95644125503",
"uid": "FTgzbZ9uWBTkiZK9kqLZaAIhEDv1" <- remove this, not needed.
},
As you can see, each child node has a key of the user id. But, you are also storing the user id as a child node as well. They key is the uid and will always be available so no need for duplication there and the child node should be removed.
Based on comments, this is a much better structure
/users
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1
"batteryStatus": 22,
"latitude": 40.9910537,
"longitude": 29.020425,
"timeStamp": 1556568633477,
"fcmToken": "fp09-Y9ZAkQ:APA91bFgGB1phr4B9gZScnz7ngpqTb5MchgWRFjHmLCVmWGMJVsyFx0rtrz7roxzpE_MmuSaMc4is-XIu7j718qjRVCSHY4PvbNjL1LZ-iytaeDP0oa8aJgE02wET3cXqKviIRMH",
"name": "Skander",
"phoneNumber": "+95644125503",
"conversationUid": "-L_w2yi8gh49GppDP3r5",
"friendStatus": "STATUS_ACCEPTED",
"notify": true,
"phoneNumber": "+915377588674",
and then, to keep track of a users friends, it becomes this
/userFriends
zzV6DQSXUyUkPHgENDbZ9EjXVBj2 //this user
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1: true //their friend
IRoo0lbhaihioSSuFETngEEFEeoi: true //another friend
To load this users friends, we read the data at /userFriends/this_users_id and then iterate over the child nodes loading the data for display in the tableView
Lets start with an object that will be used to hold each friends data, and then an array that will be used as a tableView Datasource
class FriendClass {
var uid = ""
var name = ""
//var profilePic
//var batteryStatus
init(withSnapshot: DataSnapshot) {
self.uid = withSnapshot.key
self.name = withSnapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"
}
}
var myFriendsDataSource = [FriendClass]()
Then a functions to read the users node, iterate over the users friends uid's and read in each users data, populating the FriendClass object and storing each in an array. Note that self.ref points to my firebase.
func loadUsersFriends() {
let uid = "zzV6DQSXUyUkPHgENDbZ9EjXVBj2"
let myFriendsRef = self.ref.child("userFriends").child(uid)
myFriendsRef.observeSingleEvent(of: .value, with: { snapshot in
let uidArray = snapshot.children.allObjects as! [DataSnapshot]
for friendsUid in uidArray {
self.loadFriend(withUid: friendsUid.key)
}
})
}
func loadFriend(withUid: String) {
let thisUserRef = self.ref.child("users").child(withUid)
thisUserRef.observeSingleEvent(of: .value, with: { snapshot in
let aFriend = FriendClass(withSnapshot: snapshot)
self.myFriendsDataSource.append(aFriend)
})
}
Now that we have the code to read in the data, you also want to watch for changes. There are a number of options but here's two.
1) I'll call this brute force.
Simply attach a .childChanged observer to the /users node and if something changes, that changed node is passed to the observer. If the key to that node matches a key in myFriendsDataSource array, update that user in the array. If no match, then ignore it.
func watchForChangesInMyFriends() {
let usersRef = self.ref.child("users")
usersRef.observe(.childChanged, with: { snapshot in
let key = snapshot.key
if let friendIndex = self.myFriendsDataSource.firstIndex(where: { $0.uid == key} ) {
let friend = self.myFriendsDataSource[friendIndex]
print("found user \(friend.name), updating")
//friend(updateWithSnapshot: snapshot) //leave this for you to code
}
})
}
2) Selective observing
For this, we simply attach an .childChanged observer to each friend node - and that can be done within the code example from above
func loadFriend(withUid: String) {
let thisUserRef = self.ref.child("users").child(withUid)
thisUserRef.observeSingleEvent(of: .value, with: { snapshot in
let aFriend = FriendClass(withSnapshot: snapshot)
self.myFriendsDataSource.append(aFriend)
//add an observer to this friends node here.
})
}
One last thing: I didn't address this
"friendStatus": "STATUS_ACCEPTED",
I would think that only friends you accepted are in the friends list so the use is a tad unclear. However, if you want to use it you could do this
/userFriends
zzV6DQSXUyUkPHgENDbZ9EjXVBj2 //this user
FTgzbZ9uWBTkiZK9kqLZaAIhEDv1: "STATUS_ACCEPTED"
IRoo0lbhaihioSSuFETngEEFEeoi: "STATUS_DECLINED"
and then as you're itering over friends to load, ignore the ones that are declined.
If you MUST keep your current structure (which I do NOT recommend) the techniques in this answer will work for that structure as well, however, it will be a lot more code and you're going to be moving around a lot of unneeded extra data so the Firebase bill will be higher.

How to make network calls from Siri Intent Extension?

I am trying to integrate Siri from my app. Actually my requirement is do some UDP call with my server but as it was not happening I tried with simple network call with URLSession and URLRequest. For testing I am trying to visit google.com and print the response, but the retured data from the completion handler is not convertible to String and is returning nil. Is the anything I need to add extra either in the Info.plist file or in other places to make the network calls succeed in Intent Extension ?
In the official documentation also there is no mention of this. The code I am using is simple actually but still I am pasting that below:
let session = URLSession.shared
let task = session.dataTask(with: URLRequest(url: URL(string: "https://www.google.com/")!), completionHandler: { (tcpData, response, error) in
if error != nil {
print("tcp error \(error!.localizedDescription)")
}
if let res = response as? HTTPURLResponse {
print(res.statusCode)
}
if tcpData != nil {
print(String(data: tcpData!, encoding: String.Encoding.utf8) ?? "N/A")
}
})
task.resume()
completion(TurnOnNodeAppIntentResponse.init(code: TurnOnNodeAppIntentResponseCode.success, userActivity: nil))
here is the response is always nil though statusCode is 200.
There is nothing wrong with your code. Not all data can be converted to a String. You can read more about that in this answer. Just hitting https://www.google.com/ doesn't return a string. However, if you really want to print the a string of the data from https://www.google.com/ just use print(tcpData!.base64EncodedString()) and you'll get something like: PCFkb2N0eXBlIGh0bWw+PGh0bWwgaXRlbXNjb3BlPSIiIGl0ZW10eXBlPSJodHRwOi8vc....
Switch that URL to an open API like the SpaceX API and you'll get a valid string.
{
"flight_number": 83,
"mission_name": "Amos-17",
"mission_id": [
],
"launch_year": "2019",
"launch_date_unix": 1565131920,
"launch_date_utc": "2019-08-06T22:52:00.000Z",
"launch_date_local": "2019-08-06T18:52:00-04:00",
"is_tentative": false,
"tentative_max_precision": "hour",
"tbd": false,
"launch_window": 5280,
"rocket": {
"rocket_id": "falcon9",
"rocket_name": "Falcon 9",
"rocket_type": "FT",
"first_stage": {
"cores": [
{
"core_serial": "B1047",
"flight": 3,
"block": 5,
"gridfins": false,
"legs": false,
"reused": true,
"land_success": null,
"landing_intent": false,
"landing_type": null,
"landing_vehicle": null
}
]
},
"second_stage": {
"block": 5,
"payloads": [
{
"payload_id": "Amos-17",
"norad_id": [
],
"reused": false,
"customers": [
"Spacecom"
],
"nationality": "Israel",
"manufacturer": "Boeing Satellite Systems",
"payload_type": "Satellite",
"payload_mass_kg": 6500,
"payload_mass_lbs": 14330.05,
"orbit": "GTO",
"orbit_params": {
"reference_system": "geocentric",
"regime": "geostationary",
"longitude": 17,
"semi_major_axis_km": null,
"eccentricity": null,
"periapsis_km": null,
"apoapsis_km": null,
"inclination_deg": null,
"period_min": null,
"lifespan_years": 15,
"epoch": null,
"mean_motion": null,
"raan": null,
"arg_of_pericenter": null,
"mean_anomaly": null
},
"uid": "UerI6qmZTU2Fx2efDFm3QQ=="
}
]
},
"fairings": {
"reused": false,
"recovery_attempt": true,
"recovered": true,
"ship": "GOMSTREE"
}
},
"ships": [
"GOMSTREE",
"GONAVIGATOR"
],
"telemetry": {
"flight_club": null
},
"launch_site": {
"site_id": "ccafs_slc_40",
"site_name": "CCAFS SLC 40",
"site_name_long": "Cape Canaveral Air Force Station Space Launch Complex 40"
},
"launch_success": true,
"links": {
"mission_patch": "https://images2.imgbox.com/a0/ab/XUoByiuR_o.png",
"mission_patch_small": "https://images2.imgbox.com/f1/4a/WAkSmKfY_o.png",
"reddit_campaign": "https://www.reddit.com/r/spacex/comments/cjaawx/amos17_launch_campaign_thread",
"reddit_launch": "https://www.reddit.com/r/spacex/comments/cmedgn/rspacex_amos17_official_launch_discussion_updates",
"reddit_recovery": null,
"reddit_media": "https://www.reddit.com/r/spacex/comments/cmppne/rspacex_amos17_media_thread_videos_images_gifs",
"presskit": "https://www.spacex.com/sites/spacex/files/amos-17_mission_press_kit_8_6_2019.pdf",
"article_link": "https://spaceflightnow.com/2019/08/07/spacex-launches-israeli-owned-telecom-satellite/",
"wikipedia": "https://en.wikipedia.org/wiki/Spacecom",
"video_link": "https://youtu.be/fZh82-WcCuo",
"youtube_id": "fZh82-WcCuo",
"flickr_images": [
"https://live.staticflickr.com/65535/48478269312_58dd3dc446_o.jpg",
"https://live.staticflickr.com/65535/48478269747_353dcb2e62_o.jpg",
"https://live.staticflickr.com/65535/48478119901_2de0441026_o.jpg",
"https://live.staticflickr.com/65535/48478120646_ab72c2c6c3_o.jpg",
"https://live.staticflickr.com/65535/48478120031_5aae1f6131_o.jpg",
"https://live.staticflickr.com/65535/48478269442_08479bed36_o.jpg"
]
},
"details": "SpaceX will launch Boeing built Amos-17, a geostationary communications satellite for Israeli company Spacecom. The satellite will be delivered to GTO from KSC LC-39A or possibly CCAFS SLC-40, and will replace the defunct Amos-5 at 17° E. Amos-17 carries multi-band high throughput and regional beams servicing Africa, Europe and the Middle East. The cost of this launch is covered for Spacecom by SpaceX credit following the Amos-6 incident. A recovery of the booster for this mission is not expected.",
"upcoming": false,
"static_fire_date_utc": "2019-08-01T00:00:00.000Z",
"static_fire_date_unix": 1564617600,
"timeline": null,
"crew": null
}
Also you might want to stop force unwrapping and instead use if let or guard
let session = URLSession.shared
let task = session.dataTask(with: URLRequest(url: URL(string: "https://api.spacexdata.com/v3/launches/latest")!), completionHandler: { (tcpData, response, error) in
if let err = error {
print("tcp error \(err.localizedDescription)")
}
if let res = response as? HTTPURLResponse {
print(res.statusCode)
}
if let data = tcpData {
print(String(data: data, encoding: String.Encoding.utf8) ?? "N/A")
}
})
task.resume()
completion(TurnOnNodeAppIntentResponse.init(code: TurnOnNodeAppIntentResponseCode.success, userActivity: nil))

Multiple JSON parsing from different URLs in Swift

I want to parse JSON strings from different URLs in my iOS Tab Bar app:
Parsing.swift
FirstViewController.swift (INITIAL Tab Bar View Controller)
SecondViewController.swift
...
In Parsing.swift I have various struct (TopLevel) and enum schemes I have controlled in Playground: they works perfectly. In every ViewController I have a Table View that I want to popolate with results of different JSON parsing. This is my simplified code:
FirstViewController.swift viewDidLoad()
let url = // my first URL to parse
let urlObj = URL(string: url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: urlObj!) { (data, response, error) in
do {
let results = try JSONDecoder().decode(TopLevel.self, from: data!)
... for ...
self.table.reloadData()
}
catch {
...
}
}
task.resume()
This code works perfectly: When app first open, Table View in FirstViewController popolates with results of JSON Parsing from url. But now its time to click on second Bar Item to open SecondViewController. The code is obviously:
SecondViewController.swift viewDidLoad()
let url2 = // my second URL to parse
let urlObj2 = URL(string: url2)
let config2 = URLSessionConfiguration.default
let session2 = URLSession(configuration: config2)
let task2 = session.dataTask(with: urlObj2!) { (data2, response2, error2) in
do {
let results2 = try JSONDecoder().decode(TopLevel.self, from: data2!)
... for ...
self.table2.reloadData()
}
catch {
...
}
}
task2.resume()
Well, when I tap on second Tab Bar Item to open the SecondViewController, Table View don't popolate and XCode gives an error: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}))) But JSON text is valid.
I have tried a lot of solutions: I've changed tasks to URLSession.shared, I have used private struct and enum, I have controlled variables and costants, well, no way to parse second URL correctly. Even if I create a NEW Single View App and I copy the SecondViewController.swift code into the viewDidLoad() func, it works perfectly, so, again, its not a problem of the second URL, the JSON strings are valid. I think there is an interference between the two parsing tasks, it looks like the first corrupted the second one. What can I do? Thanks.
EDIT: this is my JSON (all fields are valid strings, I have deleted it for simplify)
{
"attributes": {
"version": "2.0",
"nodeValue": "\n"
},
"channel": {
"title": " ",
"link": " ",
"description": " ",
"lastBuildDate": " ",
"language": " ",
"copyright": " ",
"item": [
{
"title": " ",
"link": " ",
"guid": {
"attributes": {
"isPermaLink": "false",
"nodeValue": " "
}
},
"pubDate": " ",
"category": " "
},
{
"title": " ",
"link": " ",
"guid": {
"attributes": {
"isPermaLink": "false",
"nodeValue": " "
}
},
"pubDate": " ",
"category": " "
}
]
} }
As I don't have access to JSON response and Model used.
I can assume few possibilities that may cause this issue.
1) You have your model and JSON response. When you are trying to decode, there could any field in JSON response that is null and same property in your model is not made optional.
2) The model may not have same structure (properties) as JSON response.
Well, I resolved the issue changing my second URL from "WWW.myserver.net/string2.json" to "myserver.net/string2.json", simply without WWW. In this way both tasks works and parses respective strings from different URLs.

Deleting Realm Object entry if its deleted in API Response

First response in this I get two user i.e abc#gmail.com & xyz#gmail.com
[{
"email": "abc#gmail.com",
"type": "primary_email",
"linked_to": {
"_id": "DAS44564dasdDASd",
"image": null,
"company": null,
"designation": null,
"name": null
},
"active_platforms": [
"asd",
"qwe"
]
},
{
"email": "xyz#gmail.com",
"type": "primary_email",
"linked_to": {
"_id": "DAS44564dasdDASd",
"image": null,
"company": null,
"designation": null,
"name": null
},
"active_platforms": [
"asd",
"qwe"
]
}]
Now if abc#gmail.com is deleted if I do API call again then still I get abc#gmail.com in my object as it is not deleted from my realm. So how to handle such situation ?
// write request result to realm database
let entries = json["data"]
realm.beginWrite()
for (_, subJson) : (String, JSON) in entries {
let entry: AppUsers = Mapper<AppUsers>().map(JSONObject: subJson.dictionaryObject!)!
realm.add(entry, update: true)
}
do {
try realm.commitWrite()
} catch {
}
Update your logic as below. This is one of method to this.
Add one extra bool field to AppUsers model say 'active'. Update your code as below
// write request result to realm database
let entries = json["data"]
realm.beginWrite()
//Fetch all realm AppUsers objects
let allAppUsers = //TODO fetch all AppUsers objects here
for user in allAppUsers {
user.active = false
}
for (_, subJson) : (String, JSON) in entries {
let entry: AppUsers = Mapper<AppUsers>().map(JSONObject: subJson.dictionaryObject!)!
entry.active = true
realm.add(entry, update: true)
}
for user in allAppUsers {
if !user.active {
realm.delete(user)
}
}
do {
try realm.commitWrite()
} catch {
}
This sounds like an issue where the data in your Realm database has become stale as the contents no longer match what is on the server.
The Realm API realm.add(_, update: true) will update any objects that were passed to it, but simply not passing an object does not imply it should be deleted (More that you just didn't want to update it).
There's no way for Realm to automatically know if an object needs to be deleted. You'll need to be in charge of that logic yourself.
Since your mechanism for checking if an object is deleted is via its email address, you could capture the email addresses of each object you've updated, and then delete any other objects whose email address is not in there.
// write request result to realm database
realm.beginWrite()
let entries = json["data"]
var updatedEmails = [String]()
for (_, subJson) : (String, JSON) in entries {
let entry: AppUsers = Mapper<AppUsers>().map(JSONObject: subJson.dictionaryObject!)!
// Save the email we just processed
updatedEmails.append(entry.email)
realm.add(entry, update: true)
}
// Delete all objects not in the updated emails list
let realmEntries = realm.objects(AppUsers.self)
for entry in realmEntries {
if !updatedEmails.contains(entry.email) {
realm.delete(entry)
}
}
do {
try realm.commitWrite()
} catch {
}
If your REST API brings down all of your objects in their complete form each time, a much quicker solution would also be to simply empty the Realm file each time and just add the objects as new objects each time too.

Alamofire: NSLocalizedFailure error (status code 403)

I am trying to retrieve the various user ids from task api, perform a loop on them and POST the array of values to submitScore api.
Desired workflow:
User taps on table cell -> app gets the cell id and display items related to that cell -> user presses a button -> app gets stores data in the form of an array and POSTS to an submitScore api
I can retrieve the various user data with a GET request from task api but I don't know how to:
associate my retrieved ids with the cell id
store the retrieved data (user ids and score) in an array and POST it to my submitScore api in the form below
Array form for POST body:
{ "ratings": [{
"safety_rating_id": 105,
"schedule_job_id": 18,
"score": 9,
"submission_id": 27
},
{
"safety_rating_id": 105,
"schedule_job_id": 18,
"score": 9,
"submission_id": 27
}]
}
Which is why I get thrown this error:
Request failed with error: Error Domain=com.alamofire.error Code=-6003 "Response status code was unacceptable: 403" UserInfo={NSLocalizedFailureReason=Response status code was unacceptable: 403}
Code for POST:
func getTaskDetails(onCompletion: () -> (), onError: ((NSError) -> ())? = nil) {
guard let endPoint = Data.sharedInstance.submitScoreEndpoint
else { print("Empty endpoint"); return }
let user = Users()
let Auth_header = [
"Authorization" : user.token,
]
let parameters = [
"ratings" : [
[
"safety_rating_id" : 106,
"schedule_job_id" : 18,
"score" : 10,
"submission_id" : 27
],
[
"safety_rating_id" : 105,
"schedule_job_id" : 18,
"score" : 9,
"submission_id" : 27
]
]
]
Alamofire.request(.POST, endPoint, headers: Auth_header, parameters: parameters)
.validate()
.responseData {
response in
switch response.result {
case .Success(let data):
let json = JSON(data)
print(json)
onCompletion()
case .Failure(let error):
print("Request failed with error: \(error)")
onError?(error)
}
}
}

Resources