I've already searched through some of the answers that have been asked about this but none of them seem to apply/work in my situation which is why I've decided to ask the community. I am simply trying to pass the data from the table view cell to the next view controller. I have gotten as far as being able to display the information in my cells accurately however whenever i select the row it just shows the view controller with no information
I have tried to set the labels and pictures to whatever the UITableViewCell may show but it is not working. I created an NSObject class that defines the variables which is why it is confusing me as to how to pass the data through to the next view Controller.
This is my AddFriendViewController where I fetch the users from Firebase and it displays my information on the tableview
class AddFriendViewController: UIViewController {
var users = [Users]()
var databaseRef = Database.database().reference()
#IBOutlet weak var friendsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
friendsTableView.delegate = self
friendsTableView.dataSource = self
fetchUser()
}
func fetchUser() {
databaseRef.child("users").observe(.childAdded) { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = Users()
user.nameOfUser = dictionary["nameOfUser"] as? String ?? ""
user.email = dictionary["email"] as? String ?? ""
user.profileImageURL = dictionary["profileImageURL"] as? String ?? ""
self.users.append(user)
DispatchQueue.main.async {
self.friendsTableView.reloadData()
}
}
}
}
}
extension AddFriendViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.users.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let friendCell = UITableViewCell(style: .subtitle, reuseIdentifier: "friendCell")
let user = users[indexPath.row]
friendCell.textLabel?.text = user.nameOfUser
friendCell.detailTextLabel?.text = user.email
if let profileImageURL = user.profileImageURL {
let url = URL(string: profileImageURL)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print(error)
return
}
DispatchQueue.main.async {
friendCell.imageView?.image = UIImage(data: data!)
}
}.resume()
}
return friendCell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showFriendProfile", sender: self.users[indexPath.row])
self.friendsTableView.deselectRow(at: indexPath as IndexPath, animated: true)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showFriendProfile" {
if let indexPath = friendsTableView.indexPathForSelectedRow {
let dvc = segue.destination as! DetailViewController
***This is where I am confused as to what I should be doing***
//EDIT1:
print("The nameOfUser is \(user.nameOfUser!)")
print("The email is \(user.email!)")
}
}
}
}
This is my Users Class:
class Users: NSDictionary {
var nameOfUser: String?
var email: String?
var profileImageURL: String?
}
This is my DetailViewController:
class DetailViewController: UIViewController {
var nameOfUser = String()
var email = String()
var profileImageURL = UIImage()
var ref: DatabaseReference?
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var nameOfUserLabel: UILabel!
#IBOutlet weak var emailLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
nameOfUser = nameOfUserLabel.text!
email = emailLabel.text!
profileImageURL = profileImageView.image!
}
}
The obvious goal is to simply click on the cell to show the data on the next view controller. I understand similar questions have been asked in the past but I truly don't know how to use those as the solution to my problem. Any help will be greatly appreciated and please let me know if there is anything I need to clarify.
EDIT1:
I added the print statement on the prepare for segue function and noticed it is at least pulling the information but for some reason not passing it to the next view controller.
Thank you
You just need to get your sender and set the properties of the detail view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showFriendProfile" {
guard let dvc = segue.destination as? DetailViewController else {
return
}
if let user = sender as? Users {
DispatchQueue.main.async {
dvc.nameOfUserLabel.text = user.nameOfUser
dvc.emailLabel.text = user.email
let url = URL(string: user.profileImageURL!)
let data = try? Data(contentsOf: url!)
dvc.profileImageView.image = UIImage(data: data!)
}
}
}
}
1- Send the object ( Make sure to connect the segue source to the vc itself not to the cell )
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showFriendProfile" {
if let indexPath = friendsTableView.indexPathForSelectedRow {
let dvc = segue.destination as! DetailViewController
dvc.user = sender as! Users
}
}
}
class DetailViewController: UIViewController {
var user:Users! // add this then inside viewDidLoad set the labels
}
2- Don't ise URLSession.shared.dataTask(with: url!) { (data, response, error) inside cellForRowAt consider using SDWebImage
import SDWebImage // install pods then add this line top of the vc
friendCell.imageView?.sd_setImage(with: URL(string:urlStr), placeholderImage: UIImage(named: "placeholder.png"))
3- No need for DispatchQueue.main.async { inside
DispatchQueue.main.async {
self.friendsTableView.reloadData()
}
As firebase callbacks run in main thread by default
Related
I just began to learn Firebase a week ago, but right now I am facing a problem of not able to load image from Firebase to my TableViewCell. I can retrieve data such as text information and the URL of the image from Firebase Realtime Database but not able to make use of those URL in order to fire up image on the TableViewCell. May you all help me identify the problems? I can retrieve everything such as text information as well as the image URL but how can I make the image pop up on the cell? All your help would be highly appreciate!
This is the ViewController that responsible to display the TableViewCell
import UIKit
import Firebase
import FirebaseStorage
class NewsFeedViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var rubthort:String = ""
var linkRub:String?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrItem.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mycell", for: indexPath) as! NewsFeed
// textlabel
// detailtextlabel
cell.textLabel?.text = arrItem[indexPath.row].name
cell.detailTextLabel?.text = arrItem[indexPath.row].price
//cell.imageView?.image = UIImage(named: "flower")
// Get image
let id = RetrieveData()
if let imageLink = self.linkRub {
let url = URL(string: imageLink)
//let data = NSData(contentsOf: url!)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
// download hit an error so return out
if error != nil {
print(error)
return
}
DispatchQueue.main.async {
cell.imageView?.image = UIImage(data: data!)
}
}.resume()
}
return cell
}
let ref = Database.database().reference()
// Array of PlasticItem
var arrItem = [RetrieveData]()
#IBOutlet weak var tblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
retrieveData()
} // Ends of viewDidLoad
func retrieveData() {
// Getting a node from database
let retRef = ref.child("item/electronic")
// Observing data changes
retRef.observe(DataEventType.value) { (dataSnapshot) in
// Remove array item everytime there is a new reference to the data in Firebase
self.arrItem.removeAll()
// Check if there are any children or second object inside the parent object
if dataSnapshot.childrenCount > 0 {
// Loop over all children's object
for post in dataSnapshot.children.allObjects as! [DataSnapshot] {
let object = post.value as! [String: Any]
let getName = object["name"] as! String
let getPrice = object["price"] as! String
let getImage = object["itemURL"] as! String
print(getName)
print(getPrice)
print(getImage)
self.linkRub = getImage
self.arrItem.append(RetrieveData(cat: "", name: getName, price: getPrice, rub: getImage))
}
self.tblView.reloadData()
}// Ends of if statement
else if dataSnapshot.childrenCount == 0{
print("No Data Found")
}
} // Ends of retRef.observe
} // Ends of retrieveData()
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
This is the model struct
import Foundation
import UIKit
struct RetrieveData{
var cat: String
var name: String
var price: String
var rub: String?
init(){
self.cat = ""
self.name = ""
self.price = ""
self.rub = ""
}
init(cat:String, name:String, price:String, rub: String){
self.cat = cat
self.name = name
self.price = price
self.rub = rub
}
}
I'm trying to learn iOS programming so I thought it would be a good idea to emulate instagrams feed. Everyone uses this basic feed and I would like to know how to do it.
The basic idea is to have one image/text post show up in a single column. Right now I have a a single image to be shown.
I'm currently extracting the image url correctly from firebase. The only issue is that my CollectionView still is showing up empty. I started this project months ago and I forget where the tutorial is at. Please help me fill in the blanks. Here is the code:
import UIKit
import SwiftUI
import Firebase
import FirebaseUI
import SwiftKeychainWrapper
class FeedViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource{
#IBOutlet weak var collectionview: UICollectionView!
//var posts = [Post]()
var posts = [String](){
didSet{
collectionview.reloadData()
}
}
var following = [String]()
var posts1 = [String]()
var userStorage: StorageReference!
var ref : DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
posts1 = fetchPosts()
//let myIndexPath = IndexPath(row: 0, section: 0)
//collectionView(collectionview, cellForItemAt: myIndexPath)
//print(self.posts1.count)
}
func fetchPosts() -> [String]{
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference().child("posts")
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
for (_,value) in dict {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:NSDictionary]
for(key, value) in dict{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
})
})
//ref.removeAllObservers()
//uids.removeAllObservers()
print("before return")
print(self.posts1.count)
return self.posts1
override func viewDidLayoutSubviews() {
collectionview.reloadData()
}
func numberOfSections(in collectionView: UICollectionView) ->Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return posts1.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostCell", for: indexPath) as! PostCell
cell.postImage.sd_setImage(with: URL(string: posts1[indexPath.row]))
//creating the cell
//cell.postImage.downloadImage(from: self.posts[indexPath.row])
// let storageRef = Storage.storage().reference(forURL: self.posts[indexPath.row].pathToImage)
//
//
print("im trying")
//let stickitinme = URL(fileURLWithPath: posts1[0])
//cell.postImage.sd_setImage(with: stickitinme)
//cell.authorLabel.text = self.posts[indexPath.row].author
//cell.likeLabel.text = "\(self.posts[indexPath.row].likes) Likes"
return cell
}
#IBAction func signOutPressed(_sender: Any){
signOut()
self.performSegue(withIdentifier: "toSignIn", sender: nil)
}
#objc func signOut(){
KeychainWrapper.standard.removeObject(forKey:"uid")
do{
try Auth.auth().signOut()
} catch let signOutError as NSError{
print("Error signing out: %#", signOutError)
}
dismiss(animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
UPDATE
The observe call is not updating the value of posts (the dictionary). Once the observe call exits, the value of posts is set back to empty.
PostCell class as asked:
import UIKit
class PostCell: UICollectionViewCell {
#IBOutlet weak var postImage: UIImageView!
#IBOutlet weak var authorLabel: UILabel!
#IBOutlet weak var likeLabel:UILabel!
#IBOutlet weak var likeBtn:UIButton!
#IBOutlet weak var unlikeBtn:UIButton!
#IBAction func likePressed (_ sender: Any){
}
#IBAction func unlikePressed(_sender: Any){
}
}
I think the problem is:
Your collectionView dataSource is called only once. Since the image url loading is asynchronous, you will need to refresh your collectionview every time new data is appended to your datasource array like this:
self.posts.append(urlimage)
collectionView.reloadData()
or:
var posts = [UIImage](){
didSet{
collectionView.reloadData()
}
}
Hope this helps.
Edit update:
Regarding the asynchronous calls, i think you should use escaping closure that runs the code block once the network request receives a response.
First separate the network call functions like:
func fetchUsers(completion: #escaping(_ dictionary: [String: NSDictionary])->()){
let uid = Auth.auth().currentUser!.uid
let uids = Database.database().reference().child("users")
uids.observe(DataEventType.value, with: { (snapshot) in
let dict = snapshot.value as! [String:NSDictionary]
completion(dict)
})
}
func fetchURLS(completion: #escaping(_ dictionary: [String: String])->()){
let ref = Database.database().reference().child("posts")
ref.observe(DataEventType.value, with: { (snapshot2) in
let dict2 = snapshot2.value as! [String:String]
completionTwo(dict2)
})
}
Then, the parsing functions:
func parseUsers(dictionary: [String: NSDictionary]){
for (_,value) in dictionary {
if let uid = value["uid"] as? String{
self.following.append(uid)
}
}
fetchURLS { (urlDictionary) in
self.parseImageURLS(dictionary: urlDictionary)
}
}
func parseImageURLS(dictionary: [String: String]){
for(key, value) in dictionary{
for uid2 in self.following{
if (uid2 == key){
for (key2,value2) in value as! [String:String]{
//print(key2 + "this is key2")
if(key2 == "urlToImage"){
let urlimage = value2
//print(urlimage)
self.posts1.append(urlimage)
self.collectionview.reloadData()
print(self.posts1.count)
}
}
}
}
}
}
Then you add:
fetchUsers { (usersDictionary) in
self.parseUsers(dictionary: usersDictionary)
}
in viewDidLoad()
Hope this solves your problem. On a side note: I recommend using models and separating the network calls in a different file. Feel free to ask any questions.
I figured out how to do it after more searching.
I was incorrectly assuming that the CollectionView is loaded after the viewDidLoad() function is done. The helper classes for a CollectionView are called to a call of reloadData.
I observed that my reloadData call wasn't being called. In order to make this work, I add 2 lines of code to the viewDidLoad function:
collectionview.delegate = self
collectionview.dataSource = self
With this change, the images now load.
I have now tried everything (as far as I know), I even made the whole thing from scratch, but it still doesn´t work.
I have made a search bar which can search for data in firebase and display them in a tableview. If the user clicks on a profile in the search bar, a new viewcontroller shows with information about that user.
The problem is that if you start searching, then clicks on a profile, it shows the profile which started on that position in the tableview before the search happened.
This is what I see without searching, it displays the 2 profiles in firebase which is correct:
Now, when I search for the profile "Lars Larsen" it filters like it should:
However, if I now choose the profile by clicking on "Lars Larsen" it shows the profile for "Jonas Larsen", which was at the top before the search?
This is the code for my searchViewController:
import UIKit
import FirebaseDatabase
class SearchTableViewController: UITableViewController,
UISearchResultsUpdating {
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet var findKunder: UITableView!
var loggedInUser: user?
var usersArray = [NSDictionary?]()
var filteredUsers = [NSDictionary?]()
var databaseRef = Database.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
databaseRef.child("Buyers").queryOrdered(byChild: "Personnr").observe(.childAdded, with: { (snapshot) in
let key = snapshot.key
let snapshot = snapshot.value as? NSDictionary
snapshot?.setValue(key, forKey: "Personnr")
self.usersArray.append(snapshot)
//Insert rows
self.findKunder.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}) { (error) in
print(error)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
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 {
// #warning Incomplete implementation, return the number of rows
if searchController.isActive && searchController.searchBar.text != ""{
return filteredUsers.count
}
return self.usersArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let user : NSDictionary?
if searchController.isActive && searchController.searchBar.text != ""{
user = filteredUsers[indexPath.row]
}
else
{
user = self.usersArray[indexPath.row]
}
cell.textLabel?.text = user? ["Navn"] as? String
cell.detailTextLabel?.text = user?["Telefonnr"] as? String
// Configure the cell...
return cell
}
func updateSearchResults(for searchController: UISearchController) {
filterContent(searchText: self.searchController.searchBar.text!)
}
func filterContent(searchText:String)
{
self.filteredUsers = self.usersArray.filter{ user in
var fNavn = false
var personNr = false
var searchBil = false
var telefonNr = false
var korekortNr = false
if let Navn = user!["Navn"] as? String {
fNavn = Navn.lowercased().contains(searchText.lowercased())
}
if let Bil = user!["Bil"] as? String {
searchBil = Bil.lowercased().contains(searchText.lowercased())
}
if let Personnr = user!["Personnr"] as? String {
personNr = Personnr.lowercased().contains(searchText.lowercased())
}
if let Kørekortnr = user!["Kørekortnr"] as? String {
korekortNr = Kørekortnr.lowercased().contains(searchText.lowercased())
}
if let Telefonnr = user!["Telefonnr"] as? String {
telefonNr = Telefonnr.lowercased().contains(searchText.lowercased())
}
return fNavn || personNr || searchBil || korekortNr || telefonNr
}
tableView.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
let showUserProfileViewController = segue.destination as! userProfileViewController
showUserProfileViewController.loggedInUser = self.loggedInUser
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
showUserProfileViewController.otherUser = user
}
}
}
This is the code I use to show the profiles:
import UIKit
import Firebase
class ProfileViewController: UIViewController {
//Outlets
var loggedInUser:User?
var otherUser:NSDictionary?
var databaseRef:DatabaseReference!
var loggedInUserData: NSDictionary?
#IBOutlet weak var Biler: UILabel!
#IBOutlet weak var Navn: UILabel!
#IBOutlet weak var kundeInfo: UILabel!
#IBOutlet weak var bilInfo: UILabel!
#IBOutlet weak var telefonNr: UILabel!
#IBOutlet weak var korekortNr: UILabel!
#IBOutlet weak var personNr: UILabel!
#IBOutlet weak var Interesse: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.databaseRef = Database.database().reference()
databaseRef.child("Buyers").child(self.otherUser?["Personnr"] as! String).observe(.value, with: { (snapshot) in
let uid = self.otherUser?["Personnr"] as! String
self.otherUser = snapshot.value as? NSDictionary
self.otherUser?.setValue(uid, forKey: "Personnr")
self.Navn.text = self.otherUser?["Navn"] as? String
self.bilInfo.text = self.otherUser?["Bil"] as? String
self.telefonNr.text = self.otherUser?["Telefonnr"] as? String
self.Interesse.text = self.otherUser?["Interesse"] as? String
self.personNr.text = self.otherUser?["Personnr"] as? String
self.korekortNr.text = self.otherUser?["Kørekortnr"] as? String
}
// Do any additional setup after loading the view.
)}
Please let me know if you need any other information. I hope you can help.
If the search bar is active and it does contain text, you should pass a user to ProfileViewController from the filteredUsers array and not usersArray.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
[...]
if let indexPath = tableView.indexPathForSelectedRow {
if searchController.isActive && searchController.searchBar.text != "" {
showUserProfileViewController.otherUser = filteredUsers[indexPath.row]
} else {
showUserProfileViewController.otherUser = usersArray[indexPath.row]
}
}
}
On a side note, you shouldn't us NSDictionary in Swift. Use Swift's Dictionary instead (for your case, if would be [String: Any]).
If I'm understanding your code correctly, your issue is here:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
let showUserProfileViewController = segue.destination as! userProfileViewController
showUserProfileViewController.loggedInUser = self.loggedInUser
if let indexPath = tableView.indexPathForSelectedRow {
let user = usersArray[indexPath.row]
showUserProfileViewController.otherUser = user
}
}
let user = usersArray[indexPath.row] // this is wrong
Since you filtered the results if the search bar is active you have to use your updated datasource
let user = filteredUsers[indexPath.row]
Basically, you're passing the wrong information before you segue.
So I built an app which loads the news into the tableView cells.
Now I want the user to be able to open individual article.
To do that I passed the selected cells using prepareForSegue method and it works but partially.
It passes the title and image properly but the full text is shown partially, to be precise it is shown as in the cells.
Here is my table of news class:
import Alamofire //Framework for handling http requests
import UIKit
import AlamofireImage
class NewsTableViewController: UITableViewController {
//Custom struct for the data
struct News {
let title : String
let text : String
let link : String
let imgUrl : String
init(dictionary: [String:String]) {
self.title = dictionary["title"] ?? ""
self.text = dictionary["text"] ?? ""
self.link = dictionary["link"] ?? ""
self.imgUrl = dictionary["imgUri"] ?? ""
}
}
//Array which holds the news
var newsData = [News]()
// Download the news
func downloadData() {
Alamofire.request("https://api.sis.kemoke.net/news").responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result) // result of response serialization
//Optional binding to handle exceptions
self.newsData.removeAll() // clean the data source array
if let json = response.result.value as? [[String:String]] {
for news in json {
self.newsData.append(News(dictionary: news))
}
self.tableView.reloadData()
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
downloadData()
tableView.rowHeight = 100
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newsData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? newsCellTableViewCell
let news = newsData[indexPath.row]
cell?.headline.text = news.title
Alamofire.request(news.imgUrl).responseImage { response in
debugPrint(response)
print(response.request as Any)
print(response.response as Any)
debugPrint(response.result)
let cellImage = response.result.value
if let image = response.result.value {
print("image downloaded: \(image)")
}
cell?.thumbnailImage.image = cellImage
}
print(news.imgUrl)
return cell!
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showArticle" {
let nextScene = segue.destination as! ArticleViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedCells = newsData[indexPath.row]
nextScene.articleTitleString = selectedCells.title
nextScene.receiveFullText = selectedCells.title
//Downloading an image to be displayed in a single article
Alamofire.request(selectedCells.imgUrl).responseImage { response in
debugPrint(response)
print(response.request as Any)
print(response.response as Any)
debugPrint(response.result)
let cellImage = response.result.value
nextScene.articleImage.image = cellImage!
}
}
}
}
}
And here is my destination view controller for the single article in which I am passing the information
class ArticleViewController: UIViewController {
#IBOutlet weak var articleTitle: UILabel!
var articleTitleString = ""
#IBOutlet weak var articleImage: UIImageView!
#IBOutlet weak var fullText: UITextView!
var receiveFullText = ""
override func viewWillAppear(_ animated: Bool) {
articleTitle.text = articleTitleString
fullText.text = receiveFullText
}
}
And this is what happens
http://imgur.com/2GQddeW
http://imgur.com/jos3VhE
See? The full text is not shown even though the server is returning full text.
I did test this by creating a textView in another view controller and get the text from the server and it worked fine.
The issue looks like it's copying a layout of the label in the cell and displaying what is in that label.
Also a tried putting another label in to the cell to load the text init and it worked properly, than after tapping a cell it displayed what was in that label.
What I want is to load a full text when this segue happens.
nextScene.articleTitleString = selectedCells.title
nextScene.receiveFullText = selectedCells.title
You are passing the title twice instead of the full text...
i am trying to pass an image from one view controller to another but i am getting an error in prepare for segue function
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let post = posts[indexPath.row]
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)as? collectionViewCellBooks {
if let img = booksVC.imageCache.object(forKey: post.imageUrl as NSString) {
cell.configureCell(post: post, img: img)
return cell
}else {
cell.configureCell(post: post)
return cell
}
}
else {
return collectionViewCellBooks()
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showImage", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "showImage"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems!
let indexPath = indexPaths[0] as IndexPath
let vc = segue.destination as! newViewController
// vc.image = self.posts[(indexPath as NSIndexPath).row]
vc.image = self.posts[indexPath.row]
}
class newViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var image = UIImage()
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = self.image
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
this is my Post class
class Post {
private var _caption: String!
private var _imageUrl: String!
private var _postKey: String!
var caption: String {
return _caption
}
var imageUrl: String {
return _imageUrl
}
var postKey: String {
return _postKey
}
init(caption: String, imageUrl: String) {
self._caption = caption
self._imageUrl = imageUrl
}
init(postKey: String, postData: Dictionary<String, AnyObject>) {
self._postKey = postKey
if let caption = postData["title"] as? String {
self._caption = caption
}
if let imagesUrl = postData["imageURL"] as? String {
self._imageUrl = imagesUrl
}
}
}
title and imageURL are saved on firebase database
You are getting the error because you are not sending an image to the new viewController but an instance of your Post class, which by the way doesn't even contain an image (only an imageURL). You have to extract the image from the server first before you can parse it anywhere.
You should parse the whole post as you are doing it right now and download the image via the postID directly in the new ViewController. (in case you saved the image in Firebase storage) I always end up parseing the whole object because later in the development you maybe decide to show more properties in the newViewController. If you parsed the whole object you don't have to change your code structure anymore.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "your Identifier" {
if let vc = segue.destination as? NewViewController {
if let post = sender as? Post {
vc.post = post
}
}
}
}
in your didSelectIdemAt function you need to change the sender of the performSegue function:
performSegue(withIdentifier: "your Identifier", sender: post)
now your newViewController has a little bit more code but that is how i do it and it works stable.
let reference = FIRDatabase.database().reference()
reference.child("posts").child("<postID>").observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in
print(snapshot.value)
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots {
if let postsDict = snap.value as? Dictionary<String, AnyObject> {
if let imageURL = postsDict["imageURL"] as? String {
let httpsReference = FIRStorage.storage().reference(forURL: imageURL)
httpsReference.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) in
if error != nil {
print("error... couldn't get picture from Server \(error.localizedDescription)")
} else {
let image = UIImage(data: data!)
self.img = image! // you need to create this variable somewhere in your viewController Class before this code
//"your UIImageVIew.image" = img AND THAT IS IT
}
}
}
}
}
}
Can you try with following change in preparefor segue method.. let me know
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
{
if segue.identifier == "showImage"
{
let indexPaths = self.collectionView!.indexPathsForSelectedItems!
let indexPath = indexPaths[0] as IndexPath
let vc = segue.destinationViewController as! newViewController
let post = posts[indexPath.row]
if let img = booksVC.imageCache.object(forKey: post.imageUrl as NSString) {
vc.image = img
}
}
}
class newViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var image = nil
override func viewDidLoad() {
super.viewDidLoad()
if self.image {
self.imageView.image = self.image
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}