Why won't my image parse into my imageView? - ios

I am trying to parse a image from a url the url is
https://a.ppy.sh/9795284
it doesn't have a specific image extension as far as i can tell, it's just a link my current code (which works for getting the username and when I print the user_id i do get 9795284 so I know the code works (I also already get other information I wanted to get since as the username however I can not for the life of me get the users image to show here is my code for dealing with parsing
fetchCoursesJSON { (res) in
switch res {
case .success(let playerinfo):
playerinfo.forEach({ (player) in
print(player.username)
DispatchQueue.main.async {
self.myLabel.text = player.username
self.avatar.image = UIImage(named: "https://a.ppy.sh/\(player.user_id)")
}
})
case .failure(let err):
print("Failed to fetch courses:", err)
}
}
I expected the output to show the users profile pick in the avatar image but it does not it's just blank.

You need to download the image first, you can do this by using a lib like SDWebImage, AlamofireImage, Kingfisher or using the native URLSession
The UIImage(named:) is used when the resource is in your assets.

The UIImage(named:) will attempt to retrieve the image from your app.. not from the internet. Here is some code that will help you retrieve the image from your url:
guard let url = URL(string: yourUrlString ?? "") else { return }
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
guard let data = data, error == nil else { return }
let image = UIImage(data: data)
DispatchQueue.main.async {
self.avatar.image = image
}
}).resume()

Related

Display Image downloaded from downloadURL generated by Firebase

I need to display the images that have been stored on the storage on Firebase. Right now, I only tracked the images using the link generated by function downloadURL:
func UploadImage(imageData: Data, path: String, completion: #escaping (String) -> ()){
let storage = Storage.storage().reference()
let uid = Auth.auth().currentUser?.uid
storage.child(path).child(uid ?? "").putData(imageData, metadata: nil) { (_, err) in
if err != nil{
completion("")
return
}
// Downloading Url And Sending Back...
storage.child(path).child(uid ?? "").downloadURL { (url, err) in
if err != nil{
completion("")
return
}
completion("\(url!)")
}
}
}
So all I can get is a hyperlink that is like: https://firebasestorage.googleapis.com/v0/b/getting-started-20f2f.appspot.com/o/profile_Photos%2FGQ1KR9H1mLZl2NAw9KQcRe7d72N2?alt=media&token=473ce86c-52ba-42ec-be71-32cc7dc895d7.
I refer to the official documentation, it seems that only when I have the name of the image file can I download it to an ImageView or UIImageView object. However, the link does not make any sense to me, so what can I do?
EDIT
I actually tried a solution provided by the official documentation:
func imageDownloader(_ imageURL: String) {
let store = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let imageRef = store.child(imageURL)
var myImageView = UIImageView()
imageRef.getData(completion: { (error, data) in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Data for "images/island.jpg" is returned
let image = UIImage(data: data!)
}
})
}
But it suggests that I need to change something because Cannot convert value of type 'DataSnapshot' to expected argument type 'Data'.
If you're storing the image paths in Firestore, actually the exact file name does not matter if there is only one file available under the fork. So you just need to specify the path.
To then download the image from Storage, construct the path and download:
let uid = Auth.auth().currentUser?.uid
Storage.storage().reference().child("the\path\to\your\uid\collection").child(uid).getData(maxSize: 1048576, completion: { (data, error) in
if let data = data,
let img = UIImage(data: data) {
// do something with your image
} else {
if let error = error {
print(error)
}
// handle errors
}
})
You are uploading to Storage.storage(), but then in your imageDownloader, you're attempting to use Database.database(), which has a similar-looking API, but is, in fact, different.
Make sure to use Storage.storage() and that the closure parameters are in the order data, error in.
Finally, right now in your imageDownloader, it doesn't look like you're doing anything yet with var myImageView = UIImageView(), but keep in mind that you won't have access to the UIImage until the async getData completes.
Store your images at Firebase Storage & then retrieve using this code.
Storage.storage().reference.child("ProfilePhotos").child("ImageName").downloadURL {(url, _) in
DispatchQueue.main.async {
guard let url = url else { return }
imageView.setImage(with: url, placeholder: UIImage(named: "dummyImage"))
}
}

Completion Handler to trigger collectionView Reload once Images are downloaded - Xcode [SWIFT]

I'm using a code I got off here to download some images and present them in a collection view.
Heres the code:
func downloadImage (url: URL, completion: () -> Void){
let session = URLSession(configuration: .default)
let downloadPicTask = session.dataTask(with: url) { (data, response, error) in
if let e = error {
print("Error downloading image \(e)")
} else {
if let res = response as? HTTPURLResponse {
print("Downloaded image with response code \(res.statusCode)")
if let imageData = data {
let image = UIImage(data: imageData)
self.globalImages.append(image!)
print("what does this say?-->", self.globalImages.count)
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
completion()
downloadPicTask.resume()
}
And I'm calling the download image in view did load where URL is the URL. (this URL works and I can download image).
downloadImage(url: url) { () -> () in
collectionView.ReloadData()
}
The completion handler I've tried calls reloadData() way too soon. I'm wanting it to be called when the image is finished downloading? so then the image can be displayed as soon as it's downloaded.
What is wrong with this code?
Please help!
You would call the completion handler as soon as you have the image. So, in your code:
if let imageData = data {
let image = UIImage(data: imageData)
self.globalImages.append(image!)
print("what does this say?-->", self.globalImages.count)
// call the completion handler here
Be aware, though, that you are likely to have other issues caused by data sharing across multiple threads, and also that your idea of storing the downloaded images successively in an array (globalImages) is not likely to work correctly.

Showing image from URL in iOS app [duplicate]

This question already has answers here:
Loading/Downloading image from URL on Swift
(39 answers)
Closed 5 years ago.
EDIT 3: Please also read my comment in the "answered" tagged answer. I think I won't use my synchronous method but change to the suggested asynchronous methods that were also given!
Ok I am struggling with some basic concepts of showing images from an URL from the internet on my app.
I use this code to show my image on an UIIamgeView in my ViewController:
func showImage() {
let myUrlImage = URL(string: linkToTheImage)
let image = try? Data(contentsOf: myUrlImage!)
imageView1.image = UIImage(data: image!)
}
Now basically I have the following question:
Is the whole image downloaded in this process?
Or works the UIImageView like a "browser" in this case and doesn't download the whole picture but only "positions" the image from the URL into my UIImageView?
EDIT:
The reason I asked is, I am basically doing a quiz app and all I need in the view is an image from a URL for each question - so it's no difference if I do it asynchronous or synchronous because the user has to wait for the image anyways. I am more interested in how do I get the fastest result:
So I wanted to know if my code really downloads the picture as a whole from the URL or just "Positions" it into the UIImageView?
If in my code the picture is downloaded in its full resolution anyways, then you are right, I could download 10 pictures asynchronously when the player starts the quiz, so he hopefully doesn't have to wait after each answer as long as he would wait when I start downloading synchronously after each answer.
Edit 2:
Because my Question was tagged as similar to another some more explanation:
I already read about synchronous and asynchronous downloads, and I am aware of the downsides of synchronous loading.
I am more interested in a really basic question, and I get the feeling I had one basic thing really wrong:
My initial thought was that if I open a link in my browser, for example this one,
https://cloud.netlifyusercontent.com/assets/344dbf88-fdf9-42bb-adb4-46f01eedd629/68dd54ca-60cf-4ef7-898b-26d7cbe48ec7/10-dithering-opt.jpg
the browser doesn't download the whole picture. But I guess this isn't the case? The whole picture is downloaded?
Never use Data(contentsOf:) to display data from a remote URL. That initializer of Data is synchronous and is only meant to load local URLs into your app, not remote ones. Use URLSession.dataTask to download image data, just as you would with any other network request.
You can use below code to download an image from a remote URL asynchronously.
extension UIImage {
static func downloadFromRemoteURL(_ url: URL, completion: #escaping (UIImage?,Error?)->()) {
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil, let image = UIImage(data: data) else {
DispatchQueue.main.async{
completion(nil,error)
}
return
}
DispatchQueue.main.async() {
completion(image,nil)
}
}.resume()
}
}
Display the image in a UIImageView:
UIImage.downloadFromRemoteURL(yourURL, completion: { image, error in
guard let image = image, error == nil else { print(error);return }
imageView1.image = image
})
You can do it this way. But in most cases it is better to download the image first by yourself and handle the displaying then (this is more or less what the OS is doing in the background). Also this method is more fail proof and allows you to respond to errors.
extension FileManager {
open func secureCopyItem(at srcURL: URL, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) {
try FileManager.default.removeItem(at: dstURL)
}
try FileManager.default.copyItem(at: srcURL, to: dstURL)
} catch (let error) {
print("Cannot copy item at \(srcURL) to \(dstURL): \(error)")
return false
}
return true
}
}
func download() {
let storagePathUrl = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("image.jpg")
let imageUrl = "https://www.server.com/image.jpg"
let urlRequest = URLRequest(url: URL(string: imageUrl)!)
let task = URLSession.shared.downloadTask(with: urlRequest) { tempLocalUrl, response, error in
guard error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("error")
return
}
guard FileManager.default.secureCopyItem(at: tempLocalUrl!, to: storagePathUrl) else {
print("error")
return
}
}
task.resume()
}

Image URL to UIImage Not Working

let url = URL(string: (pinsFIREBASE[marker.snippet!]?.imageURL)!)
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() {
self.postImage.image = UIImage(data: data)
}
}
task.resume()
I have the following code that takes a url from firebase, in the form http://i.imgur.com/nkomPpP.jpg, and is supposed to turn that url into a UIImage that can be placed on a view. However, while extracting the text from the firebase object works, parsing the image URL doesn't seem to be working as I get an empty view. What am I doing wrong?
I know why, your code works. The problem is your image link. Your imageURL's HTTP type. iOS don't like HTTP type request because it's not safe.
Plan A: Try a HTTPS type image link, it works.
Plan B: Add "App Transport Security Settings" in project info ,and set "Allow
Arbitrary Loads" yes in "App Transport Security Settings" dictionary.
I suggested use Plan A, that's Apple want iOSDev to do.
You need to remove the () from after DispatchQueue.main.async(). Try this:
let url = URL(string: (pinsFIREBASE[marker.snippet!]?.imageURL)!)
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
self.postImage.image = UIImage(data: data)
}
}
task.resume()

Firebase Object Not Found

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

Resources