when my app wants to download avatar(profile image) it will crash and show me the Error but my image is not nil But the application detect that its nil here is the Error massage
fatal error: unexpectedly found nil while unwrapping an Optional value
and here is the print of my image Data and image that proves the image is not nil
, {0, 0}
10059 bytes
and here is my codes for downloading Avatar(profile Image)
let avatarUrl = URL(string: "http://example.com/uploads/avatar/\(EmailSignInViewController.avatar)")!
let session = URLSession(configuration: .default)
// Define a download task. The download task will download the contents of the URL as a Data object and then you can do what you wish with that data.
let downloadPicTask = session.dataTask(with: avatarUrl) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
print("Downloaded personal picture with response code \(res.statusCode)")
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
print(imageData)
print(profileViewController.userImage)
if #available(iOS 10, *) {
profileViewController.userImage = UIImage(data: imageData )!
} else {
profileViewController.userImage = UIImage(named: "user.jpg")!
}
// Do something with your image.
} else {
print("Couldn't get image: Image is nil")
}
}
else {
print("Couldn't get response code for some reason")
}
}
}
downloadPicTask.resume()
Related
I'm trying to extract the image data from a UIImageView so I can upload it to Firebase Storage. However, iv.image?.jpegData() is returning nil. I'm using the standard Kingfisher library method to add the image from the URL to the UIImageView.
Here's my code:
let url = URL(string: "https://pbs.twimg.com/profile_images/1229497999392477186/BMXkjVEJ_400x400.jpg")
let iv = UIImageView()
iv.kf.setImage(with: url)
if let png = iv.image?.jpegData(compressionQuality: .leastNormalMagnitude){
filePath.putData(png, metadata: nil){ metadata, error in
print("metadata: \(metadata) |error: \(error)") // doesn't print
}
}
Any idea why iv.image?.jpegData() is nil? I've also tried iv.image?.pngData() and that is also nil.
As
iv.kf.setImage(with: url)
is asynchronous iv.image?.jpegData()/iv.image?.pngData() will be nil until the image is loaded from the server
setImage doesn't change the image property automatically. It has to potentially download the image from the Internet, which takes time.
Luckily, you can know when the download is completed by adding a completionHandler:
iv.kf.setImage(with: url, completionHandler: { result in
guard case .success(let imageResource) = result else {
// an error has occurred!
return
}
if let png = imageResource.image.jpegData(compressionQuality: .leastNormalMagnitude){
filePath.putData(png, metadata: nil){ metadata, error in
print("metadata: \(metadata) |error: \(error)") // doesn't print
}
}
})
As #Sh_Khan has explained you need to wait for the async call to finish. Here's is the fix:
let url = URL(string: "https://pbs.twimg.com/profile_images/1229497999392477186/BMXkjVEJ_400x400.jpg")
let iv = UIImageView()
iv.kf.setImage(with: url) { _ in
if let png = iv.image?.jpegData(compressionQuality: .leastNormalMagnitude){
filePath.putData(png, metadata: nil){ metadata, error in
print("metadata: \(metadata) |error: \(error)")
}
}
}
In my project, I show a UITableView, which currently has text describing a show's name and genre loading from a remote JSON file.
That all works. What I want next is to use the URL from the JSON file and load a thumbnail next to each show.
Using a tutorial, I have added a function to download the remote image with a print to test if it's successful.
if let shows_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let shows_obj = shows_list[i] as? NSDictionary
{
let show_name = shows_obj["show"] as? String
let show_genre = shows_obj["genre"] as? String
let show_image = shows_obj["thumbnail"] as? String
TableData.append(show_name! + " | " + show_genre!)
let testPictureURL = URL(string: show_image!)!
let session = URLSession(configuration: .default)
// Here's the download task where I'm grabbing the image
let downloadPicTask = session.dataTask(with: testPictureURL) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
if let res = response as? HTTPURLResponse {
print("Downloaded picture with response code \(res.statusCode)")
if let imageData = data {
// Now I know I have data, so I think I can use UIImage to convert it into an image
let image = UIImage(data: imageData)
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadPicTask.resume()
}
There are three items in the JSON array, and I get three printed statements that the picture was download: but the image does not appear.
My theory: since this is a table, maybe I have to add this as an accessory, but there isn't an image accessory subclass.
I am new to Swift -- do you have any ideas about how I should append this uploaded image to the table.
This is probably being caused by the asynchronous behavior of URLSession so when the requested image returns the view is already loaded.
To solve that, you can use a callback, for instance:
func myFunction(completion: (returnedImage -> UIIMage) -> Void){
//...
let downloadPicTask = session.dataTask(with: testPictureURL) { (data, response, error) in
//...
let image = UIImage(data: imageData)
completion(returnedImage: image)
//...
}
downloadPicTask.resume()
}
}
By using a callback, let's say that you have a method called myFunction(completion:), so now when you call the method you can handle whatever comes back from completion:
myFunction { (image) in
DispatchQueue.main.async { cell.imageView.image = image }
}
I have the following code inside cellForRowAt method to fetch image and load into the cell's imageView. The image is confirmed to be downloaded from the print statements, but image is not showing in the cell. Please help me.
let request = URLRequest(url: URL(string: imageURL)!)
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest) {(data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
print("Downloaded image with response code \(res.statusCode)")
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
let image = UIImage(data: imageData)
// Do something with your image.
DispatchQueue.main.async {
cell.imgView.contentMode = .scaleAspectFit
cell.imgView.image = image
}
print("image received")
} else { print("Couldn't get image: Image is nil") }
} else { print("Couldn't get response code for some reason") }
}
}
dataTask.resume()
I think you just missing a reload of your cell's subviews (imageView) to show the image. You also probably want to keep track of the right cell.
cell.tag = indexPath.row //after you init the cell
DispatchQueue.main.async {
if cell.tag == indexPath.row
cell.imgView.contentMode = .scaleAspectFit
cell.imgView.image = image
cell.setNeedsLayout()
}
Guys i was making a simple application using Firebase and i was uploading an image and also downloading it sometime later. Uploading works perfectly well but when i try to download an error occurs that says. Object profile_pics not found. I have created a folder named profile_pics and i store the image inside that folder. The image is there but gives error while downloading. Here is the screen shot.
Here is what is in the console.
Error -: Object profile_pics does not exist.
Here is the code to download the image.
let storage = FIRStorage.storage().reference(forURL: "gs://dd-dd-dd.appspot.com/profile_pics/\(profileURL)")
print("Path Full \(storage.fullPath)")
storage.data(withMaxSize: 11 * 1024 * 1024, completion: {
(data, error) in
if let error = error{
print("Error -: \(error.localizedDescription)")
}
else{
let image = UIImage(data: data!)
cell.profileImageView.image = image
}
})
What could be the possible error? If you please guide me through this.
I recover it this way.
let url = URL(string: "\(ImageUrlSavedinDatabase)")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.sync() {
self.profilepicimageview.image = UIImage(data: data)
self.actIndicator.stopAnimating()
}
}
task.resume()
Does that work?
Niall
I'm having a problem with my code. I am trying to download a picture through a StringBuilder and then set it to a UIImage I seem to get a problem and I hope someone can see what I have done wrong.
setUI:
uiMovieTitle.text = self.movies![movieIndex].title
var finalImageUrl = StringBuilder()
let session = URLSession(configuration: .default)
let downloadPicTask = session.dataTask(with: finalImageUrl) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
print("Downloaded cat picture with response code \(res.statusCode)")
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
let image = UIImage(data: imageData)
// Do something with your image.
uiMoviePoster.image = image
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadPicTask.resume()
}
StringBuilder
func StringBuilder() -> (String){
let posterBase = "http://image.tmdb.org/t/p/w1920"
let linkEnd = self.movies?[movieIndex].posterPath
var finalLink = ""
finalLink = posterBase + linkEnd!
return finalLink
}
I do also have another download which gets me a list of movies(JSON) and is crucial for the StringBuilder.
The compiler is complaining because the function SwiftBuilder returns a String and there are multiple methods on URLSession named dataTask(with:completion:), but none of them take a String for the first argument.
If you need SwiftBuilder to continue to return a string for some other part of your code, then for here you'll need to convert that string to a URL.
Something like the following should work:
let session = URLSession(configuration: .default)
let imageUrlString = StringBuilder()
if let imageUrl = URL(string: imageUrlString) {
let downloadPicTask = session.dataTask(with: imageUrl) { (data, response, error) in
// The download has finished.
And so on... let me know if that makes sense.