uncaught exception of type NSException with AlamoFireImage when url isn't an image - swift

I am using AlamofireImage to display images in a UITableViewCell
typealias boolAndAnyCompletion = (_ success: Bool, _ value: Any?) -> Void
class ImageHelper {
func fetchImage(url:String, completion: #escaping boolAndAnyCompletion) {
Alamofire.request(url).responseImage { response in
if let image = response.result.value {
completion(true, image)
} else {
completion(false, "No image")
}
}
}
}
This is mostly working fine. I am taking a url from a JSON object and attempted to fetch image at the url. Mostly this works fine and either returns image as expected or fails if the url string is 404 or otherwise invalid.
However today I started getting my app crashing with
libc++abi.dylib: terminating with uncaught exception of type NSException
I narrowed this down to the above method where my JSON response was giving me a url in error that was not pointing to an image.
if if the url I got for an image was "https://bbc.co.uk/news/" that that causes the crash. However if I search for an image at "https://www.google.co.uk/maps/" that fails as expected without crashed and dealt with by error handling.
I know that the best solution is for only correct image urls to be put in JSON but were dealing with humans doing that and mistakes may happen. So, Is there a reason one would 'fail correctly' which the other crashed my app? How can I prevent this crash on some invalid urls?

I found the solution to my problem and not surprised I got no answer as the problem wasn't above. I look at previous answer here and set an exception break point.
My app is also using Realm (which didn't seem relevant at first). I was populating UITableViewCell with data from Realm. Then I downloaded JSON and created new objects and deleted old realm ones.
The exception break point then stopped on
#throw RLMException(#"Object has been deleted or invalidated.")
In the cocoapod. As I was saving a string or the url and not the url in realm I'm guessing the cell started download, was then invalidated and assuming thats what caused the crash.

Related

Firebase Database connection was forcefully killed by the server. Will not attempt reconnect. Reason: Firebase error. (Swift iOS)

This is a block of code I'm using in my Xcode project. I'm trying to access data from my firestore database, however this block of code keeps on bringing up the error:
Firebase Database connection was forcefully killed by the server. Will not attempt reconnect. Reason: Firebase error. Please ensure that you spelled the name of your Firebase correctly
It's only this block of code that brings up the error. When I delete it, it's fine and the error goes away (but obviously the code won't be executed), and I really have no idea how to fix it.
Database.database().reference().child("cPosts").observe(.value)
{ (snapshot) in
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]
{
for data in snapshot
{
self.posts.removeAll()
print(data)
if let postDict = data.value as? Dictionary<String, AnyObject>
{
let key = data.key
let post = CompPost(postKey: key, postData: postDict)
self.posts.removeAll()
self.posts.append(post)
}
}
}
self.tableView.reloadData()
You tagged with google-cloud-firestore, but your code is accessing the Realtime Database. While both databases are part of Firebase, they are completely separate and the API for one will not work on the other.
So if you are indeed using Cloud Firestore, update your code to use the API to read from that database as shown here: https://firebase.google.com/docs/firestore/query-data/listen

Unable to return value via Platform Channel when using Swift Callback Handlers

I am working with Flutter and Swift. I'm trying to authorize a credit card using the AuthrizeNet SDK, which unfortunately, does not natively support Flutter. To get around this, I created a Platform Channel in my iOS AppDelegate, which I successfully managed receive data in from Flutter. My question now is how can I return that data from inside the callback handler of the authorizing function (from the AuthorizeNet SDK)? When trying to call the Flutter result function, the Swift compiler throws this error: Escaping closure captures non-escaping parameter 'result'. Here's my code:
handler!.getTokenWithRequest(request, successHandler: { (inResponse:AcceptSDKTokenResponse) -> () in
let paymentResponseModel: PaymentResponseModel = PaymentResponseModel.init(
token: inResponse.getOpaqueData().getDataValue(),
resultCode: inResponse.getMessages().getResultCode(),
tokenResultDescription: inResponse.getOpaqueData().getDataDescriptor(),
messageCode: inResponse.getMessages().getMessages()[0].getCode(),
messageText: inResponse.getMessages().getMessages()[0].getText()
)
result(String(data: try! JSONEncoder().encode(paymentResponseModel), encoding: String.Encoding.utf8))
}) { (inError:AcceptSDKErrorResponse) in
let paymentResponseModel: PaymentModelErrorResponse = PaymentModelErrorResponse.init(
code: inError.getMessages().getResultCode(),
message: inError.getMessages().getMessages()[0].getCode(),
details: inError.getMessages().getMessages()[0].getText()
)
result(String(data: try! JSONEncoder().encode(paymentResponseModel), encoding: String.Encoding.utf8))
}
I've tried different way of calling the result function outside of the getTokenWithRequest function, but I couldn't get it to work. I'm fairly new to Swift programming, so I apologize if this question is vague or has a simple solution. Thank you!
The problem is that the successHandler will be called in the future (as a callback), but result must be called immediately and you must return from the method of your code snippet immediately. So, how do you get the success/error response back? You have to make a call from native to Dart when the the token response becomes available. Then, at the Dart end, you'll have to hang about until that response call is made when you can update your app state, and the UI.
It becomes a bi-directional method channel like this:
---token request--->
<---result----------
<---token response--
----result--------->
Neither of the results contains much information, but could be used to convey errors. For example, if the first result comes back false, something went wrong and the Dart end shouldn't expect the token response - it won't happen.

WKWebView & Swift 3 - set cookie using evaluateJavaScript

I have been trying to set a cookie for WKWebView using Swift 3 in order to pass a device token to a server.
The code I've been trying to get working in order to set the cookie is as follows:
wkWebView.evaluateJavaScript("document.cookie='access_token=your token';domain='your domain';") { (data, error) -> Void in
print("data: \(data)")
print("error2: \(error)")
wkWebView.reload()
}
However, I'm stuck here because this code produces the following error output:
error2: Optional(Error Domain=WKErrorDomain Code=4 "A JavaScript exception occurred" UserInfo={WKJavaScriptExceptionLineNumber=0, WKJavaScriptExceptionMessage=SecurityError (DOM Exception 18): The operation is insecure., WKJavaScriptExceptionSourceURL=undefined, NSLocalizedDescription=A JavaScript exception occurred, WKJavaScriptExceptionColumnNumber=0})
I ended up setting the cookie by injecting a script into WKWebView at runtime, which sets the Firebase device token, which is the string I want to pass to my server, as a local storage item.
The code I've ended up with is as follows;
To set the local storage in WKWebView:
let addCookieScript="localStorage.setItem('device', '\(self.tokenFirebase)');\nconsole.log(localStorage.getItem('token'));\nconsole.log(localStorage.getItem('userId'));\n"
let script: WKUserScript = WKUserScript(source: addCookieScript as String, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
Adding the script to the WKWebView:
userContentController.addUserScript(script)
After this it is just a matter of loading the WKWebView as normal, and to monitor the local storage of the session through the Safari Developer Tool

Swift completion handler for network request causing SIGABRT

I'm using a completion handler to preform a network request, Once the network request is completed I add the result to a dictionary i've constructed that contains other information pertaining to the result. Then I call a function to change the text of the labels in my view controller. The code I'm using is:
requestCalculateTotals(data["id"] as! String, pickupDate: data["pickup_date"] as! String, dropoffDate: data["dropoff_date"] as! String){
(calculateData: NSDictionary) in
self.data.addEntriesFromDictionary(calculateData as [NSObject : AnyObject])
self.refreshDetails()
}
This causes a SIGABRT error and I dont understand why? I've tested the completion handler and the network request and they both work, I can print the result data and it contains the data I expect. The refreshDetails function works outside of the completion handler but then it won't be waiting for the network request.
Is there something I've missed when constructing the completion handler or is there a there a better way I could wait for a network request?
EDIT I get the error: "This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release." How could I add my refreshDetails function in the main thread when the network request is complete?

WatchKit Retrieve Multiple URL Images

I am creating a conversation thread using WatchKit 2.0 and am having difficulty downloading multiple images within a conversation. I am able to get a single image using the WatchConnectivity sendMessage. I can get back NSData which I can use for the UIImage.
When there was two different images in the conversation thread, neither of those calls retrieve the image properly. The code I use to fire off the message is
if WCSession.isSupported() {
// Set the session to default session singleton
session = WCSession.defaultSession()
// Fire the message to iPhone app
session!.sendMessage(["action": "getImage", "url": message.media.filename], replyHandler: { (response) -> Void in
// Extract the image data of the boarding pass
if let data = response["messageData"] as? NSData {
row.image.setImage(UIImage(data: data))
}
, errorHandler: { (error) -> Void in
// Print error
print(error)
})
}
I attempted using another thread with
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0))
But that didn't help either. I found a post Load image from URL on WatchKit, but the NSURLSession never completed, even with only one image.
How can I retrieve multiple images from different URLs?
Are you requesting both images from the same sendMessage call? There is a size limit for how large the NSData object can be, and it's only a few megabytes. You might want to try to break the requests to retrieve the images into two separate calls.
Also, is there any error message printed from your error handler?