When I run data = try! Data(contentsOf: url) my app crashes, and I'm getting this error. I tried to add the UIConstraintBasedLayoutDebugging breakpoint but it didn't help a lot.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
2019-09-23 15:59:55.228440-0600 Biobot[15968:547259] -[LGSideMenuController isLoading]: unrecognized selector sent to instance 0x7f9cf90a1a00
Warning: hit breakpoint while running function, skipping commands and conditions to prevent recursion.
error: Execution was interrupted, reason: breakpoint 4.1.
The process has been returned to the state before expression evaluation.
I don't even have an [LGSideMenuController isLoading] in my code. I'm really lost this time because the code worked just fine this morning. I updated my xcode to version 11, I don't know if that could be causing the problem
Update:
You should use Data(contentsOf: url) only when loading data from local storage (so only url that starts with file://). When you are loading data from the Internet you should use URLSession:
URLSession.shared.dataTask(with: url) { (data, response, error) in
DispatchQueue.main.async { //all changes to UI must be called on main thread
if let error = error {
print("Error: \(error)")
return
}
//transform your data and update UI
self.label.text = "Loaded data: \(data)"
}
}.resume()
where self.label.text = "Loaded data: \(data)" is some example of what you can do with your fetched data.
Try to avoid try!. Instead of it use do{} catch {}. Your code probably won't work as expected (it will not fix the problem, but you will be able to get more details). So in your code do:
do {
data = try Data(contentsOf: url)
} catch {
print("\(error)")
}
For me, your error doesn't look like related to data loading. It looks more like an issue with memory handling, as you have a pointer that is pointing to an instance of LGSideMenuController and you (or one of the libraries that you are using) try to call isLoading method on it.
Related
I am using this code
let url = URL(string: "http://image.tmdb.org/t/p/w185" + movie.poster_path!) // https://www.themoviedb.org/talk/568e3711c3a36858fc002384
print(url!)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
DispatchQueue.main.async {
self?.movieImage.image = UIImage(data: data!)
}
}
from this stack overflow post. I have a URL with an image on it, I would like to use that URL to bring the image into my app and have it show up in a
#IBOutlet weak var movieImage: UIImageView!
but for some reason, I am getting an error saying that data is nil. Why would data be nil if the URL is valid? Is this an issue with the contentsOf function or am I doing something wrong here?
If you try changing your URL declaration to be: let url = URL(string: "http://image.tmdb.org/t/p/w185//nBNZadXqJSdt05SHLqgT0HuC5Gm.jpg") it works as expected. So perhaps you are not assembling the URL correctly?
I would print whatever URL you're creating and try visiting the website to see if it is actually correct
I’d suggest not using try? (which discards any meaningful error data) and instead use try wrapped in a do-catch block, and in the catch block, examine what the error is. Right now, you’re flying blind.
Or, better, use URLSession.shared.dataTask(with:) and look at the error in the completion handler.
You asked:
... but why is this such a bad thing [to use Data(contentsOf:)] if it is the background thread?
Yes, by dispatching this to a global queue you’ve mitigated the “don’t block the main thread” problem. But Data(contentsOf:) doesn’t provide much diagnostic information about why it failed. Also, it ties up one of the very limited number of worker threads that GCD draws upon. If you exhaust the worker thread pool, then GCD won’t be able to do anything else until it’s freed up. Using URLSession offers the chance to do more meaningful diagnostics and avoids blocking GCD worker threads.
So, I would suggest removing all of those ! forced unwrapped operators and not using Data(contentsOf:). Thus, I might suggest something like:
guard
let path = movie.poster_path,
let baseURL = URL(string: "http://image.tmdb.org/t/p/w185")
else {
print("problem getting path/URL")
return
}
let url = baseURL.appendingPathComponent(path)
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else {
print("network error:", error ?? "Unknown error")
return
}
guard 200..<300 ~= response.statusCode else {
print("invalid status code, expected 2xx, received", response.statusCode)
}
guard let image = UIImage(data: data) else {
print("Not valid image")
return
}
DispatchQueue.main.async {
self?.movieImage.image = image
}
}.resume()
Then, by displaying the error, if any, we’ll see what the problem was. FWIW, the above network request identifies three types of errors, which might be helpful for diagnostic purposes:
Basic network errors
HTTP errors
Content errors (not an image)
I need to handle a core data crash. My code got crashed on the managedObjectContext.save().
But catch block did not catch any exception. To avoid the crash how can I write my Catch block better Here is my code.
do {
try managedObjectContext.save()
}
catch let error as NSError {
Print.print("Error saving data store: \(error)")
}
This is the sample for saving data using CoreData .This may helps you .
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
if let entity = NSEntityDescription.entity(forEntityName: "Employees", in: context){
let myItem = NSManagedObject(entity: entity, insertInto: context)
myItem.setValue(nameTF.text, forKey: "names")
myItem.setValue(15655, forKey: "mobileNo")
do {
try context.save()
}catch let nserror as NSError{
print("ERROR: Coredata error \(nserror)")
}
}
This really looks like you messed up with your initialization of context, persistent store and its coordinator. You would do best looking into that. There are similar posts already on SO like this one.
More importantly you will not intercept such exception with try-catch in Swift. Realistically the Swift try-catch does not have anything to do with exceptions but is a high level API for you to intercept reported errors. In your case you just intercept the error that may be reported when saving your data into database. But the error came from a bit deeper as it seems.
To go a step further the whole core data is still completely in objectiveC which has completely different system for throwing exceptions and although those exceptions MAY be intercepted with objectiveC try-catch the same exception will not be intercepted by the one from Swift. What this system did is only replaced entering of pointer to error into method: .save(&error) which was used in objectiveC. And your catch block will trigger only when this error is non-null.
I'm trying to write a simple Quick Look Preview Extension for my UIDocument-based iOS app.
The problem is that in my implementation of preparePreviewOfFile(at:completionHandler:) my attempt to open the UIDocument based on the URL I'm being handed is failing. I instantiate my document with the file URL and call open(completionHandler:) but I'm not getting any data, and I'm seeing a console message that the file coordinator has crashed.
All of this works fine in my actual app; it's just the Quick Look Preview Extension implementation that's having trouble. Is there something special I have to do to open a UIDocument from inside a Quick Look Preview Extension? Apple doesn't provide any sample code; in WWDC 2017 video 229 they just gloss over the whole thing.
EDIT: Curiouser and curiouser. I created a simplified testbed app that displays a Quick Look preview with UIDocumentInteractionController, along with my custom Quick Look Preview Extension. On the Simulator, the preview works! On the device, it doesn't. It looks like, when I tell my document to open, its load(fromContents:ofType) is never even called; instead, we are getting a pair of error messages like this:
The connection to service named com.apple.FileCoordination was invalidated.
A process invoked one of the -[NSFileCoordinator coordinate...] methods but filecoordinationd crashed. Returning an error.
I was able to work around the issue by not calling open on my UIDocument. Instead, I call read directly, on a background thread, like this:
func preparePreviewOfFile(at url: URL, completionHandler handler: #escaping (Error?) -> Void) {
DispatchQueue.global(qos: .background).async {
let doc = MyDocument(fileURL: url)
do {
try doc.read(from: url)
DispatchQueue.main.async {
// update interface here!
}
handler(nil)
} catch {
handler(error)
}
}
}
I have no idea if that's even legal. You'd think that just reading the document straight in, without the use of a file coordinator, would be Bad. But it does seem to work!
I found yet another workaround, using NSFileCoordinator and calling load manually to get the UIDocument to process the data:
let fc = NSFileCoordinator()
let intent = NSFileAccessIntent.readingIntent(with: url)
fc.coordinate(with: [intent], queue: .main) { err in
do {
let data = try Data(contentsOf: intent.url)
let doc = MyDocument(fileURL: url)
try doc.load(fromContents: data, ofType: nil)
self.lab.text = doc.string
handler(nil)
} catch {
handler(error)
}
}
Again, whether that's legal, I have no idea, but I feel better about it than calling read directly, because at least I'm passing through a file coordinator.
In the following scenario when reading JSON data from a file, I have the following block of code:
// Fetch URL
let url = Bundle.main.url(forResource: "sampleJSON", withExtension: "json")!
// Load Data
let data = try! Data(contentsOf: url)
// Deserialize JSON
let json = try! JSONSerialization.jsonObject(with: data, options: [])
Is this block of code correct on its own, or should would it be better practice to include it inside a do-catch block? I'm asking because I have seen scenarios when pulling data from the web using URLSession, where developers do the JSONSerialization inside of a do-catch block. Is there a reason why for doing it when using URLSession, and not when simply pulling the JSON data from a file? What is best practice for something like this?
1 - Is this block of code correct on its own, or should would it be better practice to include it inside a do-catch block?
A: This code is correct. It will work if your sampleJSON.json file is in your bundle AND the data in your JSON file is correctly formated AND the JSONSerialization succeds parsing the data provided.
2 - I'm asking because I have seen scenarios when pulling data from the web using URLSession, where developers do the JSONSerialization inside of a do-catch block. Is there a reason why for doing it when using URLSession, and not when simply pulling the JSON data from a file? What is best practice for something like this?
A: The do-catch statement is seen more often when consuming data(JSON in this case) from the web because the API might break for any reason(wrong specification of the data that must be shown, error in the web application itself, etc) and if this happens we do not want our application to crash.
I say CRASH because you used the ! which do not propagate the error to the upper layer of your application, it tries to force the operation and if fails would crash the app.
At this point you probably realized that the reason you don't see do-catch statement when consuming data from your bundle is because the app developer himself provided the JSON so I'd assume you are sure about the content of the file, but I'd still use the do-catch statement since something could go wrong and don't want my app to crash due to a silly thing like this.
TL;DR
I recommend to ALWAYS use error propagation with throws/rethrows or even the ? so you can test for nil results.
I have written a small article here with some tips and how it works in Swift 2.1, not much have changed in Swift 3.1 so you can use to study the do-catch statement.
I would rewrite the code you provided like this:
WARNING: UNTESTED CODE
enum JSONFromFileError: Error {
case fileNotInBundle(String)
case deserializationError
case getDataError(URL)
}
func json(from file: String) throws -> Any {
// Fetch URL in Bundle
guard let url = Bundle.main.url(forResource: file, withExtension: "json") else {
throw JSONFromFileError.fileNotInBundle(file)
}
// Load Data from url
guard let data = try? Data(contentsOf: url) else {
throw JSONFromFileError.getDataError(url)
}
// Deserialize JSON
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else {
throw JSONFromFileError.deserializationError
}
return json
}
do {
let myJsonObject = try json(from: "sampleJSON")
print(myJsonObject)
} catch let error {
print(error)
}
You should in general use a try-catch block for each function that is throwable. With your current code, if either of your try blocks fail (either the data can't be downloaded from the url or it is not a valid json), the forced trys will fail and result in a runtime exception.
let url = Bundle.main.url(forResource: "sampleJSON", withExtension: "json")!
do {
let data = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: data, options: [])
} catch {
//handle error
}
If you don't care about the error that would be thrown be the function, you can use try? which returns a nil when the function would throw an error. This way your code won't crash.
guard let data = try? Data(contentsOf: url) else {return}
guard let json = try? JSONSerialization.jsonObject(with: data, options: []) else {return}
Firstly, It is recommended that we wrap any functions that throws (with try) into a do-catch block. In my own opinion, I will also perform a do-catch block in case I modify the sampleJSON file without me knowing, that causes the format of the JSON to be disturbed.
Secondly,it is definitely a good practise to never use force unwrap at all in the code.
Lastly, we should always catch for serialization exceptions and throw to the caller, which eventually will inform the view to throw an error dialog.
I want to know how you guys handle errors when using a URLRequest in your app. How do you go about notifying your users that an error has occurred? Do you even notify your users at all? Do you try and reload the URLRequest again? Do you tell your users to close the current screen and open it again with an alert box? I have no clue.
Once there's an error, your app stops. So what do you do when this happens and you have a network issue, bad Json data?
What do you do when you get a "Bad Network Connection (The server is down)" or the URLSession comes back with an error and the internet connection is fine?
Please look at the code below and help me figure out what needs to be done when an error occurs.
let url = URL(string:"http://example/jsonFile.php")
var request = URLRequest(url:url!)
request.httpMethod = "POST"
let postingString = "id=\(id)"
request.httpBody = postingString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){(data, response, error) -> Void in
if error != nil {
print("error \(error)")
// *****
// What do you do here? Do you tell your users anything?
// *****
return
}
// Check for Error
if let urlContent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: .allowFragments) as! [String: AnyObject]
print("jsonResult \(jsonResult)")
}
catch{
print("JSON serialization failed")
// *****
// What do you do here? Do you tell your users anything?
// *****
}
}
}
task.resume()
It is often a bad idea to hide the errors and do nothing (see Error Hiding Anti-Pattern). Unfortunately, handling errors is not easy and can be tedious some times. Pretty code examples quickly become "uglier" when exceptions and errors have to be handled. It takes time to learn to do it well.
In the case of network connections, you would want to wrap your requests into asynchronous methods that take a completion callback as parameter. This callback will often receive a successful result or an error, sometimes wrapped in an enum to remove ambiguity (see Result as an example).
Once you know a network request has failed, you can present that information to the user in a clean, informational but non-obstructive way. To find out what other applications do in this scenario, turn on Airplane Mode in your phone and poke around.
Here are some examples:
Apple Music
Facebook Messenger