passing object data between viewcontrollers in swift - ios

I'm learning how to pass object data between viewcontrollers, and my source is:
firstly the class which represents the objects Flyer
class Flyer{
var title: String!
var desc: String!
var imageUrl: String!
init(dictionary: [String: AnyObject]) {
title = dictionary["title"] as? String
desc = dictionary["desc"] as? String
imageUrl = dictionary["imageUrl"] as? String
}
}
now the mainViewController class:
class MainViewController: UIViewController, UITableViewDataSource {
#IBOutlet var tableview:UITableView!
let apiClient = ApiClient()
var flyers: [Flyer]!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
apiClient.mainService.getList() { flyers, error in
if flyers != nil {
self.flyers = flyers
self.tableview.reloadData()
} else {
print("error: \(error)")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.flyers?.count ?? 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mainObjectCell") as! MainTableViewCell
cell.mainObject = self.flyers?[indexPath.row]
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailSegue" {
let detailViewController = segue.destinationViewController as! DetailMainViewController
if let indexPath = tableView.indexPathForCell(sender as! MainTableViewCell) {
detailViewController.detailString = self.flyers?[indexPath.row]
}
}
}
}
the output of this class is an error, ambiguous use of tableview(_:numbersOfRowsInSection:) in the let indexPath
the detailViewController class:
class DetailMainViewController: UIViewController {
#IBOutlet weak var detailMainLabel: UILabel!
var detailString: String?
var receivedCellIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
detailMainLabel.text = detailString
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I would like to know how to solve the error in the mainViewController class and how to pass the desc property of the flyer object to the detailViewController and show it in the label field

Related

Swift: Show data from tableView to another ViewController (JSON, Alamorife, AlamofireImage)

I'm trying to do an app in which the data were obtained from JSON.
In the picture below you can see the project:
Project
If we click on the photo opens the details page. The problem is because I do not know how to pick up the data shown in the details page. Please help me.
Here is the code
import UIKit
import Alamofire
import AlamofireImage
import SwiftyJSON
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate {
#IBOutlet weak var searchbarValue: UISearchBar!
weak open var delegate: UISearchBarDelegate?
#IBOutlet weak var tableView: UITableView!
var albumArray = [AnyObject]()
var url = ("https://jsonplaceholder.typicode.com/photos")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.searchbarValue?.delegate = self
Alamofire.request("https://jsonplaceholder.typicode.com/photos").responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar[].arrayObject {
self.albumArray = resData as [AnyObject]; ()
}
if self.albumArray.count > 0 {
self.tableView.reloadData()
}
}
}
}
public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) // called when text ends editing
{
callAlamo(searchTerm: searchbarValue.text!)
}
func callAlamo(searchTerm: String)
{
Alamofire.request("https://jsonplaceholder.typicode.com/photos").responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar[].arrayObject {
self.albumArray = resData as [AnyObject]; ()
}
if self.albumArray.count > 0 {
self.tableView.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return albumArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CostumTableViewCell
let title = albumArray[indexPath.row]
cell?.titleLabel?.text = title["title"] as? String
//cell?.url?.image = UIImage(data: title as! Data)
let imageUrl = title["thumbnailUrl"] as? String
//print(imageUrl)
let urlRequest = URLRequest(url: URL(string: imageUrl!)!)
Alamofire.request(urlRequest).responseImage { response in
if let image = response.result.value {
// print("image downloaded: \(title["url"])")
cell?.url?.image = image
}
}
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let indexPath = self.tableView.indexPathForSelectedRow?.row
let vc = segue.destination as! DetailsViewController
//here should be the code
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Also you can see the DetailsViewController code:
import UIKit
class DetailsViewController: UIViewController {
var image2 = UIImage()
var title2 = String()
#IBOutlet var mainImageView: UIImageView!
#IBOutlet var songTitle: UILabel!
override func viewDidLoad() {
songTitle.text = title2
mainImageView.image = image2
}
}
You can easily pass value from tableview to detail view using the below code :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let indexPath = self.tableView.indexPathForSelectedRow
let cell : CostumTableViewCell = self.tableView.cellForRow(at: indexPath!) as! CostumTableViewCell
let vc = segue.destination as! DetailsViewController
vc.image2 = cell.url.image!
vc.title2 = cell.titleLabel.text!
}
class ViewController: UIViewController ,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate {
var customArr = [CustomElement]()
var arr = [Any]()
// In viewDidLoad , you can append element to customArr
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var image = customArr[indexpath.row].image
var title = customArr[indexpath.row].title
arr.append(image)
arr.append(title)
performSegue(withIdentifier: "showDetails", sender: arr)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let indexPath = self.tableView.indexPathForSelectedRow?.row
if segue.identifier = "showDetails" {
if let vc = segue.destination as! DetailsViewController {
vc.arr = sender
}
}
//here should be the code
}
}
class DetailsViewController: UIViewController {
var arr = [Any]()
}

Parse from TableVC to textView in other viewController swift

I am new in programming, and have problem. I am using parse for my array in tableview. When the row is selected i want to segue on another view controller to textView. The tableview works good but i can't get text to textView.
tableVC:
import UIKit
import Parse
class ThirdTableVC: UITableViewController {
#IBOutlet weak var refresherQuotes: UIRefreshControl!
#IBOutlet var quoteTable: UITableView!
var selectedQuote: PFObject?
var quoteItems = [PFObject]()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func updateQuotesResults(_ sender: UIRefreshControl) {
fetchQuotesData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadQuoteTexts(selectedQuote: selectedQuote)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return quoteItems.count
}
func fetchQuotesData() {
let quotesQuery = PFQuery(className: "TotalTest")
quotesQuery.whereKey("Subcategory", equalTo: selectedQuote ?? nil)
quotesQuery.findObjectsInBackground { (objects, error) in
if let realCategoryObjects = objects {
self.quoteItems = realCategoryObjects
self.tableView.reloadData()
self.refresherQuotes.endRefreshing()
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let quoteCell = tableView.dequeueReusableCell(withIdentifier: "quoteCell", for: indexPath)
let quoteItem = quoteItems[indexPath.row]
let quoteUserTitle = quoteItem.object(forKey: "TextQuote") as? String
quoteCell.textLabel?.text = quoteUserTitle
return quoteCell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQuoteDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let quoteobject = quoteItems[indexPath.row] as? NSDate
let quoteController = (segue.destination as! UINavigationController).topViewController as! DetailViewController
quoteController.detailItem = quoteobject
quoteController.navigationItem.leftBarButtonItem = splitViewController?.displayModeButtonItem
quoteController.navigationItem.leftItemsSupplementBackButton = true
}
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row tapped: \(indexPath.row)")
let selectedQuotes: PFObject = quoteItems[indexPath.row]
let FourthVC = self.storyboard?.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
FourthVC.fourthTextView.text = quoteItems[indexPath.row] as? String
self.navigationController?.pushViewController(FourthVC, animated: true)
}
func loadQuoteTexts(selectedQuote: PFObject!) {
let quoteQuery = PFQuery(className: "TotalQuote")
quoteQuery.whereKey("QuoteSubs", equalTo: selectedQuote ?? nil)
quoteQuery.includeKey("QuoteSubs")
quoteQuery.findObjectsInBackground { (result: [PFObject]?, error) in
if let searchQuoteResults = result {
self.quoteItems = searchQuoteResults
self.quoteTable.reloadData()
}
}
}
}
How can I change this?
viewController with textView:
import UIKit
import Parse
class FourthViewController: UIViewController {
var getQuote: PFObject?
#IBOutlet weak var fourthTextView: UITextView!
#IBOutlet weak var fourthLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
fourthLabel.text! = getQuote as! String
fourthTextView.text! = getQuote as! String
}
}
Please help me to passing texts
If you use pushViewController do it like that , in did selectRowAt
let MainStory: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desVC = MainStory.instantiateViewController(withIdentifier: "FourthViewController") as! FourthViewController
and now pass your text
desVC.getText = "here goes your text u want to pass"
FourthViewController
set up your var
var getText = String()
so you can finally use
self.navigationController?.pushViewController(desVC, animated: true)
so it will pass all parameters you previous add with desVC.getSomething
in FourthViewController you just need to use getText.
The problem is that you are changing from a view to another with pushViewController, by doing that your prepareForSegue won't be executed.
On your didSelectRow you need to call performSegue(withIdentifier:sender:).
You can lookup this question for more information on how to do it.

Error while passing data between two ViewControllers

I get the following error after passing data from one ViewController to another.
no data
eventStruct(title: What are we gonna do today?, date: 2017-07-13, location: House3, description: Hello beautiful people!)
2017-06-15 22:01:05.697 RUC-App 1.0[48760:5792168] Warning: Attempt to present <RUC_App_1_0.EventViewController: 0x7fb686636460> on <RUC_App_1_0.NewsfeedViewController: 0x7fb68662e6a0> whose view is not in the window hierarchy!
The code from the first ViewController:
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase
class NewsfeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var ref:DatabaseReference!,
posts = [eventStruct]()
#IBOutlet weak var tableview: UITableView!
var propertStruct : (Any)? = nil
override func viewDidLoad() {
super.viewDidLoad()
loadNews()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func loadNews() {
ref = Database.database().reference()
ref.child("events").queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
if let valueDictionary = snapshot.value as? [AnyHashable:String]
{
let title = valueDictionary["Title"]
let location = valueDictionary["Location"]
let date = valueDictionary["Date"]
let description = valueDictionary["Description"]
self.posts.insert(eventStruct(title: title, date: date, location: location, description: description), at: 0)
self.tableview.reloadData()
}
})
}
///////////////////////// Table View Content \\\\\\\\\\\\\\\\\\\\\\\\\\
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let label1 = cell.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].title
let label2 = cell.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].location
let label3 = cell.viewWithTag(3) as! UILabel
label3.text = posts[indexPath.row].date
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "showDetails"){
let secondViewController = segue.destination as? EventViewController
secondViewController?.data = sender as? eventStruct
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "showDetails", sender: posts[indexPath.row])
}
/////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
}
struct eventStruct {
let title: String!
let date: String!
let location: String!
let description: String!
}
The code of the second ViewController:
import UIKit
class EventViewController: UIViewController {
var data: eventStruct?
#IBOutlet weak var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print (data ?? "no data")
self.titleLabel.text = self.data?.title
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You should not have both triggered and manual segues happening at the same time.
Try this:
Delete your didSelectRowAt function (or comment it out), and replace prepare() with:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "showDetails"){
let secondViewController = segue.destination as? EventViewController
if let idx = tableView.indexPathForSelectedRow {
secondViewController?.data = posts[idx.row]
}
}
}

Passing data with segue in the tableViewCell

I want to passing data with segue in the tableViewCell,from BulletinBoadrViewController to BbDetailViewController
class BulletinBoadrViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var bulletinBoards = [BulletinBoard]()
override func viewDidLoad() {
super.viewDidLoad()
bulletinBoards = BulletinBoard.downloadAllBulletinBoard()
self.tableView.reloadData()
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableViewAutomaticDimension
tableView.separatorStyle = .none
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return bulletinBoards.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! BulletinBoardTableViewCell
let bulletinBoard = bulletinBoards[indexPath.row]
cell.bulletinBoard = bulletinBoard
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "gotodetail", sender: indexPath)
print("Row \(indexPath.row)selected")
}
func prepareForSegue(segue: UIStoryboardSegue, sender: Any!) {
if segue.identifier == "gotodetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let destVC = segue.destination as! BdDeatilViewController
let new = bulletinBoards[indexPath.row]
destVC.bulletinBoard = new
}
}
}
and it's BdDeailViewController
class BdDeatilViewController:UIViewController {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var contentLabel: UITextView!
#IBAction func backtobb(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
var x = [BulletinBoard]()
var bulletinBoard : BulletinBoard!{
didSet{
self.updateUI()
}
}
func updateUI() {
timeLabel.text = bulletinBoard.time
titleLabel.text = bulletinBoard.title
contentLabel.text = bulletinBoard.content
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
}
and tableViewCell's data is taking from local json file, it's BulletinBoard code
class BulletinBoard {
var title:String?
var time:String?
var content:String?
init(title:String,time:String,content:String) {
self.title = title
self.time = time
self.content = content
}
init(bulletinBoardDictionary:[String:Any]) {
self.title = bulletinBoardDictionary["title"] as? String
self.time = bulletinBoardDictionary["time"] as? String
self.content = bulletinBoardDictionary["content"] as? String
}
static func downloadAllBulletinBoard() -> [BulletinBoard] {
var bulletinBoards = [BulletinBoard]()
//get the json data from the file
let jsonFile = Bundle.main.path(forResource: "BulletinBoardData", ofType: "json")
let jsonFileURL = URL(fileURLWithPath: jsonFile!)
let jsonData = try? Data(contentsOf: jsonFileURL)
//turn the json data into foundation objects (bulletinBoards)
if let jsonDictionary = NetworkService.parseJSONFromData(jsonData) {
let bulletinBoardDictionaries = jsonDictionary["BulletinBoard"] as! [[String:Any]]
for bulletinBoardDictionary in bulletinBoardDictionaries {
let newBulletinBoard = BulletinBoard(bulletinBoardDictionary: bulletinBoardDictionary)
bulletinBoards.append(newBulletinBoard)
}
}
return bulletinBoards
}
}
Finally,it's my StoryBoard
https://i.stack.imgur.com/JcgdH.png1
Can anyone solve my problem?Thanks!
I think you should retrieve indexPath from sender in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: Any!) {
if segue.identifier == "gotodetail" {
if let indexPath = sender as? IndexPath {
let destVC = segue.destination as! BdDeatilViewController
let new = bulletinBoards[indexPath.row]
destVC.bulletinBoard = new
}
}
}
and update the UI in the viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.updateUI()
}

Passing data back to previous view controller after selecting table view cell

I'm having trouble passing data after selecting a table view cell to the previous view controller. I'm pretty much trying to change a label from the previous view controller after selecting a table view cell. Could anyone help me go about this? I'm trying to change the UITextField after selecting a cell.
UIViewController:
class WhoToOdds: UIViewController, sendBack,UITextFieldDelegate{
#IBOutlet var chosenContact: UITextField!
#IBOutlet var oddsTextBox: UITextView!
var friend: String?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
func sendNameToPreviousVC(selectedfriendName: String) {
friend = selectedfriendName
chosenContact.text = friend
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "friendList"{
let friendViewController = (segue.destinationViewController as! friendListController)
var fbRequest = FBSDKGraphRequest(graphPath:"/me/friends", parameters: nil);
fbRequest.startWithCompletionHandler { (connection : FBSDKGraphRequestConnection!, result : AnyObject!, error : NSError!) -> Void in
if error == nil {
println("Friends are : \(result)")
PFUser.currentUser()?["friend_list"] = result
PFUser.currentUser()?.save()
print(result)
var resultdict = result as! NSDictionary
println("Result Dict: \(resultdict)")
friendViewController.friendArray = resultdict.objectForKey("data") as! NSArray
} }
}
}
#IBAction private func submitChallenge(sender: AnyObject) {
navigationController?.popViewControllerAnimated(true)
}
}
TableViewController:
protocol sendBack
{
func sendNameToPreviousVC(contact: String)
}
class friendListController: UITableViewController, UITableViewDataSource, UITableViewDelegate{
var friendArray:NSArray = ["a","b","c"]
var valueDict:NSDictionary = [:]
var mDelegate:sendBack?
var selectedFriend :String?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friendArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("friend", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = (friendArray[indexPath.row] as! String)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
selectedFriend = currentCell.textLabel!.text as String!
sendBackFriendList(selectedFriend!)
navigationController?.popViewControllerAnimated(true)
}
func sendBackFriendList(name: String){
self.mDelegate?.sendNameToPreviousVC(name)
}
}
Your delegate needs to be set. In your case you have to set it inside prepareForSegue method like
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "friendList"{
let friendViewController = (segue.destinationViewController as! friendListController)
friendViewController.mDelegate = self //Include this line
//rest of the code
}
}
You didn't set the delegate in your segue, so mDelegate is nil in your sendBackFriendList method

Resources