Can not display image in table view cell using firebase - swift

I can not display image using firebase in table view cell, I don't know why because my code seems to work, but not there, may anyone help me?
Note: The label Works. I created a custom cell using a cocoa touch class, then I have linked that using the notation to cell as you can see.
import UIKit
import Firebase
class PlacesTableViewController: UIViewController,
UITableViewDataSource, UITableViewDelegate{
let ref = Database.database().reference()
var PlacesRef:DatabaseReference! = nil
var SelectedRef:DatabaseReference! = nil
let storage = Storage.storage()
var postdata:[String] = [String]()
#IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
print("Here Variables")
print("Here translated Names")
PlacesRef = ref.child("Places")
let storageRef = self.storage.reference()
PlacesRef.observe(.value) { (snapshot) in
let postDict = snapshot.value as? [String : AnyObject] ?? [:]
if snapshot.exists() {
for a in ((snapshot.value as AnyObject).allKeys)!{
var now:String = ""
self.postdata.append(a as! String)
DispatchQueue.main.async{
self.tableview.reloadData()
}
}
} else {
print("we don't have that, add it to the DB now")
}
print(self.postdata) //add key to array
}
tableview.delegate = self
tableview.dataSource = self
}
func tableView(_ _tableView: UITableView, numberOfRowsInSection selection: Int) ->Int{
print(postdata)
return postdata.count
}
func tableView( _ tableview: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableview.dequeueReusableCell(withIdentifier: "cell") as! CustomTableViewCell
var image=UIImage()
let StorageRef = storage.reference()
let NationRef = StorageRef.child("Nations/\(postdata[indexPath.row]).jpg")
print("\(postdata[indexPath.row]).jpg")
NationRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print(error)
} else {
// Data for "images/island.jpg" is returned
image = UIImage(data: data!)!
print("image downloaded!")
}
}
cell.DetailLabel.text = postdata[indexPath.row]
cell.DetailImage.image = image
return cell
}
}

Let's see what happens in
func tableView( _ tableview: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableview.dequeueReusableCell(withIdentifier: "cell") as! CustomTableViewCell
var image=UIImage()
let StorageRef = storage.reference()
let NationRef = StorageRef.child("Nations/\(postdata[indexPath.row]).jpg")
// HERE we starting async web request for image data (tag 1)
NationRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print(error)
} else {
// HERE we getting image data from async request and storing it in image var (tag 3)
image = UIImage(data: data!)!
print("image downloaded!")
}
}
cell.DetailLabel.text = postdata[indexPath.row]
// HERE we setting UIImage to cell's imageView (tag 2)
cell.DetailImage.image = image
return cell
}
if printing tags we'll get tag 1, tag 2 and tag 3. It means that firstly you create empty uiimage, then set this image to cell's imageView and at last you change image to image from request (image, not cell's imageView)
I think the answer can be - replace image = UIImage(data: data!)! with cell.DetailImage.image = UIImage(data: data!)
and there are many ways to improve this method

Related

Is there any way to list user defaults datas with swift?

I am trying to do save datas like name, address with user default at main view controller. After saving data, I wanted to list all user default data at second view controller with tableview (PeopleViewController). I managed to save user default data with main view controller. But only last saved user default data can be showed at tableview while I would like to list all data at tableview. What am I doing wrong? Can you give an idea? Thank you in advance..
My second view controller / PeopleViewController
import UIKit
class PeopleListViewController: UIViewController, UITableViewDelegate,UITableViewDataSource {
var names = [String]()
var address = [String]()
let storage = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
let peopleData = storage.value(forKey: "people") as? Data
if peopleData != nil {
let decoder = JSONDecoder()
do {
let person = try decoder.decode(People.self, from: peopleData!)
names.append(person.name)
address.append(person.address)
}catch {
print(error)
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LocationCell",for: indexPath)
cell.textLabel?.text = names[indexPath.row]
cell.detailTextLabel?.text = address[indexPath.row]
return cell
}
}
My main view controller
import UIKit
class ViewController: UIViewController {
#IBOutlet var TextFields: [UITextField]!
let storage = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
let peopleData = storage.value(forKey: "people") as? Data
if peopleData != nil {
let decoder = JSONDecoder()
do {
TextFields[0].text = ""
TextFields[1].text = ""
}catch {
print(error)
}
}
}
#IBAction func createButtonTapped(_ sender: UIButton) {
let name = TextFields[0].text!
let address = TextFields[1].text!
let people = People(
name: name,
address: address
)
let encoder = JSONEncoder()
do {
let peopleData = try encoder.encode(people)
storage.setValue(peopleData, forKey: "people")
TextFields[0].text! = ""
TextFields[1].text! = ""
}catch {
print(error)
}
}
}
My People Model
import Foundation
struct People: Codable{
var name: String
var address: String
}
Right now, you are only storing one person in UserDefaults. Every time you create a new person, you are overwriting the previous value. To store many people, you need an [People]. When you decode and encode, you can encode the whole [People].
// main VC
let encoder = JSONEncoder()
let decoder = JSONDecoder()
do {
// first decode the array from the storage
let array = storage.data(forKey: "people").map { try decoder.decode([People].self, from: $0) } ?? []
array.append(people) // add the newly created person
let newArrayData = try encoder.encode(array)
storage.set(newArrayData, forKey: "people")
TextFields[0].text! = ""
TextFields[1].text! = ""
}catch {
print(error)
}
// table VC
// you don't need two parallel arrays
var people: [People] = []
let storage = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
do {
people = try storage.data(forKey: "people").map { try decoder.decode([People].self, from: $0) } ?? []
} catch let error {
print(error)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LocationCell",for: indexPath)
cell.textLabel?.text = people[indexPath.row].name
cell.detailTextLabel?.text = people[indexPath.row].address
return cell
}

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

Core Data prints saved data but not showing up on table viewcontroller

I would like to show my saved data in core data on a table view controller, the data is saved properly and prints out the details on the console but the data is noot showing up on the tableview cell, kindly please help
var charData = [SavedCharacters]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var name = String()
var house = String()
var ancestry = String()
var getImage = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
func getData(){
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "SavedCharacters")
request.returnsObjectsAsFaults = false
do{
let result = try? context.fetch(request)
for data in result as! [NSManagedObject]
{
name = data.value(forKey: "name") as! String
print(data.value(forKey: "name")as! String)
}
}
tableView.reloadData()
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return charData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dataCell", for: indexPath) as! SavedDataTableViewCell
cell.nameLabel.text = charData[indexPath.row].name!
cell.house = charData[indexPath.row].house!
cell.ancestry = charData[indexPath.row].ancestry!
// displaying image in table view cell
if let imageURL = URL(string: self.charData[indexPath.row].image!) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.charImageView.image = image
}
}
}
}
return cell
}
Definitely you've forgotten to init charData in getData() method
var charData: [CharData]
func getData(){
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "SavedCharacters")
request.returnsObjectsAsFaults = false
====> charData = []
do{
let result = try? context.fetch(request)
for data in result as! [CharData]
{
name = data.value(forKey: "name") as! String
print(data.value(forKey: "name")as! String)
===> charData.append(data)
}
}
tableView.reloadData()
}

Passing Data from one view controller to another (Image)

Error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
Destination Controller
var getImage = UIImage()
var name = String()
var gender = String()
var house = String()
var ancestry = String()
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = (charData.image)as! UIImage
nameLabel.text! = name
houseLabel.text! = house
// Do any additional setup after loading the view.
}
Source Controller
var charactersData = [Character]()
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func loadData()
{
DispatchQueue.main.async {
Alamofire.request("http://hp-api.herokuapp.com/api/characters").responseJSON(completionHandler: {
(response) in
switch response.result
{
case.success(let value):
let json = JSON(value)
print(json)
json.array?.forEach({
(character) in
let character = Character(name: character["name"].stringValue, house:character["house"].stringValue,image:character["image"].stringValue, gender: character["gender"].stringValue, ancestry: character["ancestry"].stringValue)
self.charactersData.append(character)
})
self.tableView.reloadData()
case.failure(let error):
print(error.localizedDescription)
}
})
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return charactersData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CharTableViewCell
cell.nameLabel.text = "Name: " + charactersData[indexPath.row].name
cell.houseLabel.text = "House: " + charactersData[indexPath.row].house
if let imageURL = URL(string: self.charactersData[indexPath.row].image) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.charImageView.image = image
}
}
}
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let hpc = storyboard?.instantiateViewController(withIdentifier: "CharDetails") as? CharDetailsViewController
hpc?.getImage = (charactersData[indexPath.row].image) as! UIImage
hpc?.name = charactersData[indexPath.row].name
hpc?.house = charactersData[indexPath.row].house
self.navigationController?.pushViewController(hpc!, animated: true)
}
Im trying to pass an image to another controller but it seems im getting that error, could someone kindly help me. All the other data like name and house is passing properly other than the image. Kindly please let me know where to make changes
This might work:
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = getimage // change this in view did load method
}
You are doing wrong(this is not UIImage, this is URL string so you can use this url string to download the image):
hpc?.getImage = (charactersData[indexPath.row].image) as! UIImage
Please replace UIImage to String because this is not UIImage, This is String URL to download the image
So For this You have to change getImage variable UIImage to String and pass this String to this variable
var getImage = String()
hpc?.getImage = (charactersData[indexPath.row].image) as! String
After that again download this image from URL in another controller but this way is not good so you to follow below way:
Or
You have another option like when you download the image than save it Character Struct and pass it when didselect
Process:
Add a new variable like image in Character Struct/Model
Assign downloaded image when API call in the Struct/Model
And pass this image to another controller when didSelect

How to fetch a profile image from Firebase Storage of the user who posts a new post?

I have an instagram-like app where there is a small user profile image above their image post in the main feed.
I have figured out how to fetch the user profile image of the current user, but I cannot figure out how to fetch the user profile image of the person who added the post. Please see my code below.
How do I fetch the user image who created the post?
My Firebase Database structure is:
[my app] > "posts" > post id > "description", "image", "title", "uid", "userName", "location"
My Firebase Storage structure is:
[my app] > "Users" > uid > "profile_pic.jpg"
I am using Swift 3 and Firebase.
Thank you for any advice!!
var eventPosts = NSMutableArray()
#IBOutlet weak var eventPostsTableView: UITableView!
#IBAction func logoTapped(_ sender: Any) {
}
func loadData() {
FIRDatabase.database().reference().child("events").observeSingleEvent(of: .value, with: { (snapshot) in
if let eventPostsDictionary = snapshot.value as? [String: AnyObject] {
for post in eventPostsDictionary {
self.eventPosts.add(post.value)
}
self.eventPostsTableView.reloadData()
}
})
}
override func viewDidLoad() {
super.viewDidLoad()
self.eventPostsTableView.delegate = self
self.eventPostsTableView.dataSource = self
loadData()
// Do any additional setup after loading the view, typically from a nib.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.eventPosts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! EventTableViewCell
// Configure the cell
let event = self.eventPosts[indexPath.row] as! [String: AnyObject]
cell.titleLabel.text = event["title"] as? String
cell.userNameLabel.text = event["userName"] as? String
if ("image" as? String) != nil {
let user = FIRAuth.auth()?.currentUser
let storage = FIRStorage.storage()
let storageRef = storage.reference()
let profilePicRef = storageRef.child("Users").child((user?.uid)!+"/profile_pic.jpg")
profilePicRef.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) -> Void in
if (error != nil) {
print("Unable to download image")
} else {
if(data != nil)
{
print("User already has image")
cell.userProfileImageView.image = UIImage(data: data!)
}
}
})
}
if let imageFileName = event["image"] as? String {
let imageRef = FIRStorage.storage().reference().child("images/\(imageFileName)")
imageRef.data(withMaxSize: 2 * 1024 * 1024) { (data, error) -> Void in
if error == nil {
// Success
let image = UIImage(data: data!)
cell.flyerImageView.image = image
cell.flyerImageView.clipsToBounds = true
} else {
// Error
print("Error downloading image: \(error?.localizedDescription)")
}
}
}
return cell
}
}