Load image from firebase database to cell imageview - swift

I am very new to swift so am still following tutorials to learn how things work but things are not really working out for me like in the tutorial. Am trying to load image from firebase database into cell imageview like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let userr = users[indexPath.row]
cell.textLabel?.text = userr.name
cell.detailTextLabel?.text = userr.email
if let profileImageUrl = userr.image_url {
let url = URL(string: profileImageUrl)
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async {
cell.imageView?.image = UIImage(data: data!)
}
}).resume()
}
return cell
}
but it's not working, Both name and email both loads successful but image don't and i don't know where i am getting it wrong.

Related

How to make consistent display of image in cell in tableView?

I have an image in a custom cell (called "StoryCell"), the reference to which is in a Realm database and which I am loading up in the CellForRowAt with the following code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
....
let story = stories?[indexPath.row]
if story?.storyImage.isEmpty == true {
print("Do nothing")
} else {
let path = getDocumentDirectory().appendingPathComponent(story!.storyImage)
do {
let imageData = try Data(contentsOf: path)
let retrievedImage = UIImage(data: imageData)
cell.storyImage.image = retrievedImage
} catch {
print("Error retrieving image: \(error)")
}
}
cell.delegate = self
return cell
}
However, whenever I am adding a new table item, after the eighth time the display of the images becomes inconsistent i.e. the first picture repeats on the eighth line. I know this is connected with the 'reuse' nature of cells in tableviews and have tried to resolve it using the 'if' statement in my code above, and also by 'reloading' the tableview data when the new item is added:
#IBAction func addStoryButton(_ sender: UIBarButtonItem) {
let newStory = Story()
newStory.dateCreated = Date()
self.save(story: newStory)
self.storiesTableView.reloadData()
}
However, I still get the same behaviour. Thanks in advance for any thoughts on this.
A full explanation of this issue is here: https://fluffy.es/solve-duplicated-cells/. I finally resolved with the following code in the cellForRowAt although the 'reset' code can also be placed in the 'prepareForReuse' function as indicated by Rocky. Setting the 'defaultImage' as seen in code below also helped:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "storyCell", for: indexPath) as! StoryCell
let story = stories?[indexPath.row]
//reset to default image
let defaultURL = Bundle.main.url(forResource: "test", withExtension: "jpg")
do {
let imageData1 = try Data(contentsOf: defaultURL!)
let retrievedImage = UIImage(data: imageData1)
cell.storyImage.image = retrievedImage
} catch {
print("Error retrieving defaultImage: \(error)")
}
//place saved image in storyImage
if story?.storyImage.isEmpty == true {
print("Do nothing")
} else {
let path = getDocumentDirectory().appendingPathComponent(story!.storyImage)
do {
let imageData = try Data(contentsOf: path)
let retrievedImage = UIImage(data: imageData)
cell.storyImage.image = retrievedImage
} catch {
print("Error retrieving image: \(error)")
}
}
cell.delegate = self
return cell
}
Thanks #Rocky for putting me on the right path.
prepareForReuse is the method which you are looking for.
override func prepareForReuse() {
super.prepareForReuse()
// Do your stuff here, like reset image or content of cell for reusing
self.storyImage.image = nil
}

TableView white cell after reloadData

I've a problem after load data from firebase, when i call the reload data, the table view populate with new list data but are all white and if I click I can get the data value correctly.
If I use static data all works fine.
Any suggestion? thanks!
private func loadUniversity(url: String) {
let configuration = URLSessionConfiguration.ephemeral
let session = URLSession(configuration: configuration)
let url = URL(string: url)!
let task = session.dataTask(with: url) {
(data, response, error) in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let data = data else {
return
}
do {
let decoder = JSONDecoder()
let university = try decoder.decode([UniversityJSON].self, from: data)
for item in university {
self.universityArray.append(University(name: item.university_name.trim()))
}
let queue = OperationQueue.main
queue.addOperation {
self.currentUniversityArray = self.universityArray
print(self.currentUniversityArray)
self.table.reloadData()
}
} catch {
print("Error info: \(error)")
}
}
task.resume()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? UniversityCell else {
return UITableViewCell()
}
cell.name.text = currentUniversityArray[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? UniversityCell else {
return UITableViewCell()
}
cell.name.text = currentUniversityArray[indexPath.row].name
// Put this background Color
cell.backgroundColor = .clear
return cell
}

Downloading profile image string from firebase database to an uiimage

User upload image to firebase storage and the url string is added to the firebase database,
How can I take the string in the firebase database and convert it to uiimage to use it as an image ?
The string returned from database is like this:
https://firebasestorage.googleapis.com/v0/b/ichatmessage.appspot.com/o/YNoodTnOSGXl6HkPoqhOPAopb8v1?alt=media&token=738771a5-53e3-46c2-b508-ad5cfa03e74e
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as! NewMessageCell
let user = users[indexPath.row]
cell.textLabel?.text = user.username
cell.detailTextLabel?.text = user.email
let currentID = Auth.auth().currentUser?.uid
let databaseRef = Database.database().reference().child("users").child(currentID!)
databaseRef.observe(.value) { (data) in
let dictinoray = data.value as? [String: AnyObject]
let profileImage = dictinoray!["profileimage"] as! String
cell.imageView?.image = profileImage.toImage()
print(profileImage)
}
return cell
}
extention
extension String {
func toImage() -> UIImage? {
if let data = Data(base64Encoded: self, options: .ignoreUnknownCharacters){
return UIImage(data: data)
}
return nil
}
}
I used other way by mapping and using storage downloadurl and it worked
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as! NewMessageCell
let user = users[indexPath.row]
cell.textLabel?.text = user.username
cell.detailTextLabel?.text = user.email
let storageref = Storage.storage().reference().child(user.userid)
storageref.downloadURL { (imgurl, er) in
let imagedata = try? Data.init(contentsOf: imgurl!)
cell.imageView?.layer.cornerRadius = (cell.imageView?.frame.size.width)!/2
cell.imageView?.image = UIImage.init(data: imagedata!)
}
Another option would be to load and cache the image through Kingfisher. It's how I would usually load images within a tableView that's from an API.
import Kingfisher above your class.
Then in your cellForRowAtIndexPath, set the image with Kingfisher.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as! NewMessageCell
let user = users[indexPath.row]
cell.textLabel?.text = user.username
cell.detailTextLabel?.text = user.email
let currentID = Auth.auth().currentUser?.uid
let databaseRef = Database.database().reference().child("users").child(currentID!)
databaseRef.observe(.value) { (data) in
let dictinoray = data.value as? [String: AnyObject]
let profileImage = dictinoray!["profileimage"] as! String
cell.imageView?.kf.setImage(with: URL(string: profileImage))
}
return cell
}
Not sure if you were looking for an alternative but that's another way to do it.

Swift, Stop Images from loading in table View

Here I load my images, I want to stop the images from loading when I click on the path. How can this be done? I tried setting the URL to nil but that didn't work.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as? CustomCell
let pintrestsUrl = pintrest[indexPath.row].urls?.thumb
Library().parseImages(ImagesUrlArrayPath: pintrestsUrl!, completion: { (image) -> Void in
if let imageFromCache = imageCache.object(forKey: pintrestsUrl as AnyObject ) as? UIImage {
cell?.ImageView.image = imageFromCache
}
})
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// stop images from loading
}
EDIT -- added ParseImages Function
func parseImages(ImagesUrlArrayPath: String, completion: #escaping (UIImage)-> Void) {
if let imageFromCache = imageCache.object(forKey: ImagesUrlArrayPath as AnyObject ) as? UIImage {
completion(imageFromCache)
}
else
{
if let imageURL = URL(string: (ImagesUrlArrayPath)){
DispatchQueue.global().async{
let data = try? Data(contentsOf: imageURL)
if let data = data{
let imageToCache = UIImage(data: data)
// let image = imageToCache
DispatchQueue.main.async {
imageCache.setObject(imageToCache!, forKey: ImagesUrlArrayPath as AnyObject)
completion(imageToCache!)
print("sucess")
//cell?.videoImageView.image = image //?.resizeImage(targetSize: size)
}
}
}
}
}
}
Solved this awhile back
You have to set the images to nil before loading new images on them

How to Use NSData to Get Pictures in Swift

This is my code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "news", for: indexPath)
let lebel = cell.viewWithTag(1) as! UILabel
let lebel1 = cell.viewWithTag(2) as! UILabel
lebel.text = self.titlename[indexPath.row]
lebel1.text = self.content[indexPath.row]
var image: UIImage?
if let imageURL = URL(string:self.picture[indexPath.row] ) {
do {
let imageData = try Data(contentsOf:imageURL as URL)
image = UIImage(data:imageData as Data)
} catch {
print("error")
}
}
if image != nil {
cell.imageView?.image = image
}else{
cell.imageView?.image = nil
//cell.imageView?.image = UIImage(named: "failed")
}
return cell
}
self.picture is a String array. When I make a network request, the URL I want to connect to is https://localhost:8443/news/p0.jpg. I get this error:
2017-01-11 10:11:28.888 pro[19800:2397129] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)error
But I have been using Alamofire to connect to https in other places has been very successful. What is wrong with it?
OK,I try to use URL and Data,But this has nothing to do with the error
OK,it is done! because I use Alamofire to manager the connection, so I must use alamofire to fetch the image data. Rather than the original method!!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "news", for: indexPath)
let lebel = cell.viewWithTag(1) as! UILabel
let lebel1 = cell.viewWithTag(2) as! UILabel
let pict = cell.viewWithTag(3) as! UIImageView
lebel.text = self.titlename[indexPath.row]
lebel1.text = self.content[indexPath.row]
if let imageURL = URL(string:self.picture[indexPath.row]) {
Alamofire.request(imageURL, method: .get).responseData { response in
guard let data = response.result.value else {
pict.image = nil
//cell.imageView?.image = UIImage(named: "failed")
return
}
pict.image = UIImage(data: data)
}
}
return cell
}
But so much thanks!