Alamofire, Swift: What could be causing this error? - swift

What could be causing this error?
All of a sudden out of nowhere I started getting the error below. I have reinstalled the cocoapod, cleaned the build folder, and reinstalled the app already and none of that has fixed the error.
ERROR: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
CODE:
let recoverUrl = "http://www.website.com/recover.php?email=\(emailData)&local=application"
let urlEncodedString = recoverUrl.replacingOccurrences(of: " ", with: "%20")
parseRecover(url: urlEncodedString)
//////////////
func parseRecover(url : String){ AF.request(url).responseJSON(completionHandler: { response in self.parseData(JSONData: response.data!) }) }
func parseData(JSONData : Data){
do {
var readableJSON = try JSONSerialization.jsonObject(with: JSONData, options: .mutableContainers) as! JSONObject
if let recoverJSON = readableJSON["Recover"] as? [JSONObject] {
for i in 0..<recoverJSON.count {
let JSON = recoverJSON[i]
let status = JSON["status"] as! String
let message = JSON["message"] as! String
if status == "Error" {self.Alert01("\(message)")}
else if status == "Success" { self.Alert02("\(message)") }
}}}
catch { print(error) }
}
ERROR IS OCCURING AT:
func parseRecover(url : String){ AF.request(url).responseJSON(completionHandler: { response in self.parseData(JSONData: response.data!) }) }

There's no guarantee that a response has data, so force unwrapping the value can lead to crashes. I suggest you create Decodable types to parse your responses and use Alamofire's responseDecodable method to handle your responses.
Additionally, even if you don't adopt Decodable, responseJSON already parses your response Data using JSONSerialization, so you can just access the response.result to see the output.

SOLVED: The issue was within my php file. I was using $_GET[''] and it should have been a $_POST[''] or $_REQUEST['']

Related

How to change error.localizedDescription to JSON by Swift?

In Swift I got the error from Cloud Functions.
And I caught the error like this
functions.httpsCallable("addMessage").call(["text": inputField.text]) { result, error in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
let details = error.userInfo[FunctionsErrorDetailsKey]
}
}
}
The message get like JSON format from Cloud functions.
{"message":"text is required","status":"INVALID_ARGUMENT"}
If I got the error message from Cloud functions, and I want to display to the user.
First I tried
let status = message["status"]
But I got No exact matches in call to subscript in xcode.
How do I resolve this problem?
error.localizedDescription is obviously a JSON string, you have to deserialize it
let messageJSON = error.localizedDescription
let messageDictionary = try? JSONDecoder().decode([String:String].self, from: Data(messageJSON.utf8))
let message = messageDictionary?["message"] ?? ""

How do I read the property values of a JSON error object using Combine in Swift?

All of my API endpoints return a response which looks something like this in Postman:
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Missing authentication"
}
What I would like to do is make the request, and have access to these properties in Swift. There will be some cases where I use the error message property's value in the front of the app. This will be determined by the statusCode returned.
What I have right now is this:
private var cancellable: AnyCancellable?
let url = URL(string: "http://abc336699.com/create")
self.cancellable = URLSession.shared.dataTaskPublisher(for: url!)
.map { $0.data }
Prior to this, I tried tryMap, but the type of error it returned didn't give me the flexibility I wanted. I then moved on and tried Almofire, but it seemed like an over kill for what I want to do.
I wanted to check what is being returned in the response I get, but I get the following error:
Cannot assign value of type 'Publishers.Map<URLSession.DataTaskPublisher, Data>' to type 'AnyCancellable'
I want simple access to my response errors so I can integrate the API throughout the app using combine.
I am not sure from where you will be getting your data as in JSON response there is no Key for data. Before writing below code my understanding was that you want to check error and statusCode from the mentioned JSON response and then move forward with your business logic. The below code is to give you a vague idea of how we can do that.
enum CustomError: Error {
case custom(_ error: String)
case unknownStatusCode
case errorOccurred
}
let url = URL(string: "http://abc336699.com/create")
func load() -> AnyPublisher<Data,CustomError> {
URLSession.shared.dataTaskPublisher(for: url!)
.map(\.data)
.tryMap { (data) -> Data in
let genericModel = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: AnyObject]
if let statusCode = genericModel?["statusCode"] as? String {
switch statusCode {
case "200":
guard let data = genericModel?["message"] as? Data else {
throw CustomError.custom("Parsing error")
}
return data
default:
if let error = genericModel?["error"] as? String {
throw CustomError.custom(error)
} else {
throw CustomError.unknownError
}
}
}
throw CustomError.errorOccurred
}
.decode(type: YourCustomDecodableModel.self, decoder: JSONDecoder())
.mapError({ $0 as? CustomError ?? CustomError.errorOccurred })
.eraseToAnyPublisher()
}

Getting error when trying to use Result type with delegate

Im tring to make a network call and instead of using callback I try to use delegate instead.using Result type where .Sucsess is T: Decodable and .failure is Error. passing my model in the .Sucsess is working but when trying to pass an error I get a compile error "Generic parameter 'T' could not be inferred" what am I missing ?
protocol NetworkServiceDelegate: class {
func decodableResponce<T: Decodable>(_ result: Result<T, NetworkError>)
}
let dataTask:URLSessionTask = session.dataTask(with: url) { (dataOrNil, responceOrNil, errOrNil) in
if let error = errOrNil {
switch error {
case URLError.networkConnectionLost,URLError.notConnectedToInternet:
print("no network connection")
self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))
case URLError.cannotFindHost, URLError.notConnectedToInternet:
print("cant find the host, could be to busy, try again in a little while")
case URLError.cancelled:
// if cancelled with the cancelled method the complition is still called
print("dont bother the user, we're doing what they want")
default:
print("error = \(error.localizedDescription)")
}
return
}
guard let httpResponce:HTTPURLResponse = responceOrNil as? HTTPURLResponse
else{
print("not an http responce")
return
}
guard let dataResponse = dataOrNil,
errOrNil == nil else {
print(errOrNil?.localizedDescription ?? "Response Error")
return }
do{
//here dataResponse received from a network request
let decoder = JSONDecoder()
let modelArray = try decoder.decode([Movie].self, from:
dataResponse) //Decode JSON Response Data
DispatchQueue.main.async {
self.delegate?.decodableResponce(Result.success(modelArray))
}
} catch let parsingError {
print("Error", parsingError)
}
print("http status = \(httpResponce.statusCode)")
print("completed")
}
this line generates the error, it dosnt metter if I pass my enum that cumfirms to Error or trying to pass the error from the dataTask
self.delegate?.decodableResponce(Result.failure(.networkConnectionLost))
Well, you have two problems, having to do with the question "what type is this?" Swift is very strict about types, so you need to get clear about that.
.networkConnectionLost is not an Error. It is an error code. You need to pass an Error object to a Result when you want to package up the error. For example, URLError(URLError.networkConnectionLost) is an Error.
The phrase Result<T, NetworkError> makes no sense. Result is already a generic. Your job is to resolve the generic that it already is. You do that by specifying the type.
So for example, you might declare:
func decodableResponce(_ result: Result<Decodable, Error>)
It is then possible to say (as tests):
decodableResponce(.failure(URLError(URLError.networkConnectionLost)))
or (assuming Movie is Decodable):
decodableResponce(.success([Movie()]))
That proves we have our types right, and you can proceed to build up your actual code around that example code.

WKInterfaceTable is not getting populated with Codable data

My JSON object is not getting sent to my WKInterfaceTable.
UITableView is populating correctly. Last step is to populate the WKInterfaceTable. The code is not throwing an errors in Xcode but there is a runtime crash because the cast is failing.
Edit: Thanks to Dale I fixed an error handling line so the run-time message is gone, but the same problem persists.
printing loadedData: Optional(<5b7b2273 7065616b 6572223a 224a6f68 6e222c22 7469746c 65223a22 486f7720 61726520 796f753f 222c2274 6f223a22 323a3030 222c2266 726f6d22 3a22313a 3030227d ...>)
override func willActivate() {
super.willActivate()
if(WCSession.default.isReachable) {
let message = ["getMsgData" : [:]]
WCSession.default.sendMessage(message, replyHandler:
{ (result) -> Void in
print("Requesting data from phone")
print("printing message: \(message)")
print("printing messageObjects: \(self.messageObjects)")
if result["messageData"] != nil {
let loadedData = result["messageData"]
NSKeyedUnarchiver.setClass(MessageObject.self, forClassName: "MessageObject")
do {
let loadedPerson = try? JSONDecoder().decode(MessageObject.self, from: loadedData as! Data)
self.messageObjects = [loadedPerson]
self.progTable.setNumberOfRows(self.messageObjects.count, withRowType: "MsgRowController")
//code...
}
Through the process of updating to using the Codable protocol I didn't realize I had to remove previous instances of NSKeyedArchiver/Unarchiver.

Upgraded from Kanna 2.2.1 to 4.0.2 and getting the same error

I am rewriting a project I found on Github to learn and teach myself how to use swift and pod files. I upgraded Kanna from 2.2.1 to 4.0.2 because I was getting an arm64 error.
With 4.0.2 I am getting the error:
Initializer for conditional binding must have Optional type, not 'HTMLDocument'
Call can throw, but it is not marked with 'try' and the error is not handled
I am unsure about what this error means and how to fix it. It is associated with this if statement:
if let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
}
The type signature for the method you are calling is public func HTML(html: String, url: String? = nil, encoding: String.Encoding, option: ParseOption = kDefaultHtmlParseOption) throws -> HTMLDocument. The function returns a non-Optional value, but can throw an error.
You can handle the error by either using the try? keyword to make the function return nil in case an error was thrown and make the optional binding you currently use work like this:
if let doc = try? Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8) {...
or rather use try and put the function call in a do-catch block to see the actual error in case any was thrown.
do {
let doc = Kanna.HTML(html: htmlText, encoding: String.Encoding.utf8)
for itemSize in doc.css("option[value^='']") {
let itemSizeText = itemSize.text!.lowercased()
let wishListItemSize = self.websiteInstance!.websiteWishListItem.size!.lowercased()
if itemSizeText.range(of: wishListItemSize) != nil {
print("Found size")
foundItemSize = true
let itemSizeValue = itemSize["value"]
self.websiteInstance!.viewController!.websiteBrowser!.evaluateJavaScript("document.getElementById(\"size-options\").value = \(itemSizeValue!)", completionHandler: nil)
break
}
countSize += 1
}
} catch {
print(error)
// Handle error
}