Thank you for your prompt response and thank you for your excellent video tutorials on Networking with URLSession. The best exposition I have seen on the topic for someone at my level of iOS knowledge. This is my first attempt at reaching out for assistance so if I am doing anything wrong feel free to point it out to me. While I have programming experience in the .NET world, iOS is totally new to me. Again, thank you for any help
The Application
An iPad data entry form that saves the form data to Core data and then when a timer is triggered the code checks if we have Wi-Fi, checks if the WEBAPI URL will resolve, gets a record from Core data, constructs a JSON string from it and POSTs using URLSession dataTask.
Depending on the status code returned in the completion handler âresponseâ = 201 or 500 â the code deletes from CORE data the record used to create the JSON string (for 201), checks for next record and repeats process until record count equals 0, or aborts processing (for 500) until next timer event.
The Problem
All of this worked correctly â I think - until the recent updates to
Swift 3.1
iOS 10.3.1
Xcode 8.3.2.
The build setting is iOS 10.3
Now, when the first record of the series (from 1 to X) is POSTed to the Web API, I do not appear to receive a response HTTP Status Code. My code loops to the second record to be POSTed, and I DO receive a response HTTP Status Code for this one, and those that follow.
Now whatever I do the first record retrieved from Core data gets inserted twice into the SQL Server database that the WEBAPI is talking to. When I debug the code, on first iteration, when the code gets to
URLSesion.dataTask
it jumps directly to
.resume()
And the value for âresponseâ is not set so I cannot implement the logic of what to do with the CORE data record â delete or abort. On the next iteration, âresponseâ has a value and I can implement the logic. I believe that it is for this reason that the first record is inserted twice into the SQL database. Everything else works correctly except for the doubling of first record.
Not the Problem
Both the database and the WEBAPI is in house and we have complete control over them and they have not been changed.
Limitations
While we are proficient in WEBAPI, .NET, C#, SQL Server development, this is our first IOS application.
The Code
//This function gets called by the timer event
func getData(){
let request = NSFetchRequest(entityName: âWCVisitorsâ)
do{
let results = try managerContext.fetch(request)
let visitors = results as! [NSManagedObject]
print("Visitors count: " + String(visitors.count))
if visitors.count == 0{
return
}
//fetch all
for visitor in visitors {
SourcePostalCode = visitor.value(forKey: âsourcePostalCodeâ) as! String
SourceCountry = visitor.value(forKey: âsourceCountryâ) as! String
SourceState = visitor.value(forKey: âsourceStateâ) as! String
DestinationState = visitor.value(forKey: âdestinationStateâ) as! String
VisitorPartyCount = visitor.value(forKey: âvisitorPartyCountâ) as! String
NewsletterYesNo = visitor.value(forKey: ânewsletterYesNoâ) as! String
FirstName = visitor.value(forKey: âfirstNameâ) as! String
LastName = visitor.value(forKey: âlastNameâ) as! String
EmailAddress = visitor.value(forKey: âemailAddressâ) as! String
Comments = visitor.value(forKey: âcommentsâ) as! String
EnteredTimeStamp = visitor.value(forKey: âenteredTimeStampâ) as! String
IpadName = visitor.value(forKey: âipadNameâ) as! String
Model = visitor.value(forKey: âmodelâ) as! String
iOSVersion = visitor.value(forKey: âiOSVersionâ) as! String
//if no Wi-Fi, no delete and return
let didPost = tryToPOST()
if didPost == âfalseâ {
return
}
//We call the function to POST the data stored in the variables
postTry()
//whatCode is a class level variable that is to be set by the completion handler, and interrogated for âwhat nextâ
print("What code: " + whatCode)
//if whatCode returns âfalseâ then we got return code 500 and we abort. Had to add empty string because that is what returns every time at first entry into the URLSession dataTask. This I think is the problem but how to solve it?
if whatCode == ââ || whatCode == âfalseâ{
return
}
//returned 201 so we can delete the record and loop for next record, if any
if whatCode == âtrueâ{
managerContext.delete(visitor)
do{
try managerContext.save()
}catch let error as NSError{
print(âCould not save delete (error)â)
}
}
}
}catch{
print(âFetch error: (error)â)
}
//return
}//End function called by the timer event
//function called from getData
func postTry() {
//I also tried ephemeral
let session = URLSession(configuration: .default)
let url = URL(string: âhttps://dx.nccommerce.com/xxxxxxx/xxx/XXXâ)
let postString = "SourcePostalCode=" + SourcePostalCode + "&SourceCountry=" + SourceCountry + "&SourceState=" + SourceState + "&DestinationState=" + DestinationState + "&VisitorPartyCount=" + VisitorPartyCount + "&FirstName=" + FirstName + "&LastName=" + LastName + "&EmailAddress=" + EmailAddress + "&NewsletterYesNo=" + NewsletterYesNo + "&Comments=" + Comments + "&iPadName=" + IpadName + "&Model=" + Model + "&iOSVersion=" + iOSVersion + "&EnteredTimeStamp=" + EnteredTimeStamp
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = postString.data(using: String.Encoding.utf8)
//on first iteration the code will jump from the below line to postTask.resume() and response is empty string
//on second entry everything works fine. Yes, I know that the task starts in a suspended state but I donât know what to do with that
//information to solve my problem.
let postTask = session.dataTask(with: request){data, response, error in
guard let response = response as? HTTPURLResponse else {
print("No status code created")
return
}
if (response.statusCode == 201){
self.whatCode = "true"
print("Status code: 201 - true")
}else if (response.statusCode == 500){
self.whatCode = "false"
print("Status code: 500 - false")
}
}
postTask.resume()
}
//End function postTry