The new Firebase lets you have a NSURL profile image property for the user, but I'm having trouble displaying it. Here is how I'm saving it......
let user = FIRAuth.auth()?.currentUser
if let user = user {
let changeRequest = user.profileChangeRequest()
changeRequest.photoURL = searchURL
changeRequest.commitChangesWithCompletion { error in
if let _ = error {
print("Try Again")
} else {
print("Photo Updated")
self.profileImage.image = image
}
}
}
And this is how I'm trying to retrieve it....
if let user = FIRAuth.auth()?.currentUser
{
let name = user.displayName
let pic = user.photoURL
self.displayNameLBL.text = name
if pic != nil
{
print(pic!)
let urlString: String = pic!.path!
self.profileImage.image = UIImage(named: urlString)
//self.profileImage.image = UIImage(data: pic! as NSURL)
}else
{
self.profileImage.image = UIImage(named: "imagePlaceholder")
}
}
I'm getting user.displayName but not the image.
You are trying to display an URL not an image you need to download the image first you can use this extension:
extension UIImageView {
func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .ScaleAspectFit) {
guard let url = NSURL(string: link) else { return }
contentMode = mode
NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
guard
let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
let data = data where error == nil,
let image = UIImage(data: data)
else { return }
dispatch_sync(dispatch_get_main_queue()) {
self.image = image
}
}.resume()
}
}
usage :
imageView.downloadedFrom(stringURL, contentMode: .ScaleAspectFill)
Related
I'm trying to set an image on the button from API
here my code is
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CreatGroupCollectionViewCell
cell.btn2.setImage(downloaded(link: String), for: .normal)
return cell
}
I also use an extension to download an image from the link
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
please tell me how to set an image on the button
Try using this extension to set image from url in a UIButton:
extension UIButton {
func setImageFrom(url link: String) {
guard let url = URL(string: link) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.setImage(image, for: .normal)
}
}.resume()
}
}
Use this extension to load image from url and store it to cache for faster reload.
let imageCache = NSCache<AnyObject, AnyObject>()
extension UIImageView {
func loadImageUsingCacheWithUrlString(_ urlString: String) {
self.image = nil
//check cache for image first
if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = cachedImage
return
}
//otherwise fire off a new download
guard let url = URL(string: "\(urlString)") else { return }
URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
//download hit an error so lets return out
if error != nil {
print(error ?? "")
return
}
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as AnyObject)
self.image = downloadedImage
}
})
}).resume()
}
}
I am trying to get images from a URL and append them to an array. This if my function for it:
func doStuff(html: String?){
do {
let doc: Document = try SwiftSoup.parse(html ?? "")
let priceClasses: Elements? = try doc.select("[class~=(?i)price]")
for priceClass: Element in priceClasses!.array() {
let priceText : String = try priceClass.text()
print(try priceClass.className())
print("pricetext: \(priceText)")
}
let srcs: Elements = try doc.select("img[src]")
let srcsStringArray: [String?] = srcs.array().map { try? $0.attr("src").description }
for imageName in srcsStringArray {
if (imageName?.matches("^https?://(?:[a-z0-9\\-]+\\.)+[a-z]{2,6}(?:/[^/#?]+)+\\.(?:jpg|gif|png)$"))! {
print(imageName!)
let imageView = UIImageView()
imageView.downloaded(from: imageName!) {
if let image = imageView.image {
self.imagesArray!.append(image)
} else {
print("Image '\(String(describing: imageName))' does not exist!")
}
}
}
}
} catch Exception.Error( _, let message) {
print(message)
} catch {
print("error")
}
}
This code is not working as it always exits and print <imageName> does not exist! . The weird thing is that the fileName is a correct name!
For example:
https://www.adidas.de/on/demandware.static/-/Sites-adidas-DE-Library/default/dw817801e3/Originals_Brand_Nav_Title.png
This is how I download the image from the URL:
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, finished: () -> Void) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
finished()
}
}
Does anyone have any idea why I can not append images to my array ??? Im stuck..
I fixed the issue by changing the way I load the image:
extension UIImage {
public static func loadFrom(url: URL, completion: #escaping (_ image: UIImage?) -> ()) {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url) {
DispatchQueue.main.async {
completion(UIImage(data: data))
}
} else {
DispatchQueue.main.async {
completion(nil)
}
}
}
}
}
With this I simply call:
for imageName in srcsStringArray {
if (imageName?.matches("^https?://(?:[a-z0-9\\-]+\\.)+[a-z]{2,6}(?:/[^/#?]+)+\\.(?:jpg|gif|png)$"))! {
guard let url = URL(string: imageName!) else { return }
UIImage.loadFrom(url: url) { image in
if let image = image {
print("append")
self.imagesArray.append(image)
} else {
print("Image '\(String(describing: imageName))' does not exist!")
}
}
}
}
So I have this function which loads Image from the URL and I took it from here
extension UIImageView {
func loadImageUsingCache(withUrl urlString : String) {
let url = URL(string: urlString)
if url == nil {return}
self.image = nil
// check cached image
if let cachedImage = imageCache.object(forKey: urlString as NSString) {
self.image = cachedImage
return
}
let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(style: .medium)
addSubview(activityIndicator)
activityIndicator.startAnimating()
activityIndicator.center = self.center
// if not, download image from url
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
if let image = UIImage(data: data!) {
imageCache.setObject(image, forKey: urlString as NSString)
self.image = image
activityIndicator.removeFromSuperview()
}
}
}).resume()
}
}
This works fine for an UIImageView but when I'm trying to load an Image from URL to a UIButton imageview it's not working.
userAvatarButton.imageView!.loadImageUsingCache(withUrl: "https://homepages.cae.wisc.edu/~ece533/images/airplane.png")
You can set an image on a button that way. According to apple docs:
When setting the content of a button, you must specify the title,
image, and appearance attributes for each state separately.
In other words, you have to specify the image for a specific button state. What you need to do is call UIButton.setImage to set the image.
you can try this, i think this will help you.
func imageFromUrl(_ urlString: String) {
if let url = URL(string: urlString) {
let request = URLRequest(url: url)
DispatchQueue.global(qos: .userInitiated).async {
let imageData = NSData(contentsOf: url)
DispatchQueue.main.async {
if imageData != nil {
if let img = UIImage(data: imageData as! Data){
DispatchQueue.main.async {
self.userAvatarButton.setImage(img, for: .normal)
}
}
} else {
print("error")
}
}
}
}
}
And then call like,
imageFromUrl("https://homepages.cae.wisc.edu/~ece533/images/airplane.png")
I am trying to load image for the particular cell for whose indexpath the URL is present. Have function to download the image and send it through call back method, but after callback the other cells are also getting loaded by the downloaded image. Thanks in Adv.
Here is the code sample. In method cellForItemAtIndexPath
let stationCollectionViewcell : StationCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "stationCell", for: indexPath) as! StationCollectionViewCell
if imageURL.contains("http") {
self.loadImageWithURL(url: URL(string: station.imageURL)!) { (image) in
stationCollectionViewcell.radioImgView.image = image
}
} else if imageURL != "" {
stationCollectionViewcell.radioImgView.image = UIImage(named: "station-therockfm")
} else {
stationCollectionViewcell.radioImgView.image = UIImage(named: "stationImage")
}
And the function that will download the image
func loadImageWithURL(url: URL, callback: #escaping (UIImage) -> ()) {
print("This is getting excuted loadImageWithURL")
let session = URLSession.shared
let downloadTask = session.downloadTask(with: url, completionHandler: {
url, response, error in
if error == nil && url != nil {
if let data = NSData(contentsOf: url!) {
if let image = UIImage(data: data as Data) {
DispatchQueue.main.async(execute: {
callback(image)
})
}
}
}
})
downloadTask.resume()
}
You should reset image before reusing cell, because it is reused with previous image before new is downloaded. Also, you should compare saved url with url in callback, because callback may return when cell is reused.
// reset image
override func prepareForReuse() {
super.prepareForReuse()
radioImgView.image = nil // set nil or default image
}
Add url to callback
func loadImageWithURL(url: URL, callback: #escaping (UIImage, URL) -> ()) {
print("This is getting excuted loadImageWithURL")
let session = URLSession.shared
let downloadTask = session.downloadTask(with: url, completionHandler: {
url, response, error in
if error == nil && url != nil {
if let data = NSData(contentsOf: url!) {
if let image = UIImage(data: data as Data) {
DispatchQueue.main.async(execute: {
callback(image, url!)
})
}
}
}
})
downloadTask.resume()
}
Compare url
let stationCollectionViewcell : StationCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "stationCell", for: indexPath) as! StationCollectionViewCell
if imageURL.contains("http") {
let url = URL(string: station.imageURL)!
self.loadImageWithURL(url: url) { (image, callbackUrl) in
guard url == callbackUrl else { return }
stationCollectionViewcell.radioImgView.image = image
}
} else if imageURL != "" {
stationCollectionViewcell.radioImgView.image = UIImage(named: "station-therockfm")
} else {
stationCollectionViewcell.radioImgView.image = UIImage(named: "stationImage")
}
I hope, it will run Fine.
import UIKit
let imageCache = NSCache<AnyObject, AnyObject>()
class CustomImageView : UIImageView {
var imgUrlString : String?
func loadImageWithURL(urlString : String) {
imgUrlString = urlString
guard let url = URL(string: urlString) else { return }
image = nil
if let imgFromCache = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = imgFromCache
return
}
URLSession.shared.dataTask(with: url) { (data, resposne, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.sync {
let imageToCache = UIImage(data: data!)
imageCache.setObject(imageToCache!, forKey: urlString as AnyObject)
if self.imgUrlString == urlString {
self.image = imageToCache
}
}
}.resume()
}
}
Intialize your instance with this Class.
let thumbnailImageView : CustomImageView = {
let imgView = CustomImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.image = #imageLiteral(resourceName: "taylor_swift_blank_space")
imgView.contentMode = .scaleAspectFill
imgView.clipsToBounds = true
return imgView
}()
Cells are reusing each time, also you have async call in the controller. In the downloading completion, you need to reload cell by IndexPath.
Also, reset image in prepareForReuse
override func prepareForReuse() {
super.prepareForReuse()
stationCollectionViewcell.radioImgView.image = nil
}
The best solution with async images it's to have cache
let imageCache: NSCache<NSString, UIImage> = NSCache<NSString, UIImage>()
after loading has been completed save the image:
imageCache.setObject(image, forKey: url as NSString)
and next time, when cell appears, check is image already exists in imageCache
if yes, use image from the cache, if not, download an image
Code should looks like this:
if imageURL.contains("http") {
if let image = imageCache.object(forKey: station.imageURL as NSString) {
stationCollectionViewcell.radioImgView.image = image
} else {
self.loadImageWithURL(url: URL(string: station.imageURL)!) { [weak self] (image) in
self?.imageCache.setObject(image, forKey: url as NSString)
self?.collectionView.collectionView.reloadItems(at: [indexPath])
}
}
} else if imageURL != "" {
stationCollectionViewcell.radioImgView.image = UIImage(named: "station-therockfm")
} else {
stationCollectionViewcell.radioImgView.image = UIImage(named: "stationImage")
}
I want to upload my profile picture from facebook to firebase and then want to retrieve...
my code was working well in swift 2.0 i-e
let urlPic = (data?.objectForKey("url"))! as! String
when I convert it to swift 3.0 i-e
let urlPic = ((data as AnyObject).object("url"))! as! String
There is an error
Cannot call Value of non-function type 'Any?!'
There is my complete code please help...
if let user = FIRAuth.auth()?.currentUser {
// User is signed in.
let name = user.displayName
let photoUrl = user.photoURL
let uid = user.uid
self.username.text = name
let data = try? Data(contentsOf: photoUrl!)
self.profilepic.image = UIImage(data: data!)
//------Saving in DB-----
let storage = FIRStorage.storage()
let storageRef = storage.reference(forURL: "my storage_url..")
let profilePicRef = storageRef.child(user.uid+"/userPic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
print("Unable to download the image")
} else {
if (data != nil)
{
self.profilepic.image = UIImage(data:data!)
}
}
}
if (profilepic.image == nil)
{ var profilepic = FBSDKGraphRequest(graphPath: "/me/picture", parameters: ["height":300 ,"width":300, "redirect": false], httpMethod: "GET")
profilepic?.start(completionHandler: {(connection, result, error) -> Void in
if error == nil {
let dictionary = result as? NSDictionary
let data = dictionary?.object(forKey: "data")
let urlPic = ((data as AnyObject).object("url"))! as! String
if let imageData = NSData(contentsOfURL: NSURL(string:urlPic)!) {
let profilePicRef = storageRef.child(user.uid+"/userPic.jpg")
let uploadTask = profilePicRef.putData(imageData, metadata:nil){
metadata, error in
if( error == nil){
let downloadUrl = metadata!.downloadURL
}
else { print("Error in downloading image") }
}
self.profilepic.image = UIImage(data: imageData)
}
}
})
}
} else {
// No user is signed in.
}
Thanks in advance!
In Swift use native Dictionary instead of NSDictionary and instead of object(forKey:) use subscript with Dictionary, so instead of casting result to NSDictionary cast it to [String:Any].
if error == nil {
if let dictionary = result as? [String:Any],
let dataDic = dictionary["data"] as? [String:Any],
let urlPic = dataDic["url"] as? String {
//access urlPic here
}
}
Note: In swift 3 use native Data and URL instead of NSData and NSURL.