How to use segue in navigation SWIFT Xcode? - ios

I'm building a simple dictionary app. I've gotten it to display words on UItableView while user is searching or not. I'm working on assigning each individual word with its own definition but I'm facing a trouble while setting the destination for each word at words array.
Here is part of my ViewController class and its contents:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
var wordSearch = [String]()
var wordArray: [String] = []
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "zo_words", withExtension: "txt")! // file URL for file "words_alpha.txt"
do {
let string = try String(contentsOf: url, encoding: .utf8)
wordArray = string.components(separatedBy: "\n")
} catch {
print(error)
}
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return wordSearch.count
} else {
return wordArray.count
}
Here is my wordSearch function:
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
wordSearch = wordArray.filter({$0.lowercased().prefix(searchText.count) == searchText.lowercased();})
searching = true
tableView.reloadData()
}
Cannot assign value of type 'String' to type 'ViewController' Error is raised in below function while building
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DefinitionViewController {
destination.word = wordArray[(tableView.indexPathForSelectedRow?.row)!]
class DefinitionViewController:
import UIKit
class DefinitionViewController: UIViewController {
#IBOutlet weak var lbDefinition:
UILabel!
var word: ViewController?
override func viewDidLoad() {
super.viewDidLoad()
lbDefinition.text = "\((word?.wordSearch)!)"
}
}

I think it's not applicable and recommended to take an instance from the ViewController but you can do it so easy by using the below:
Let's say you've word in your viewControllerthen you have to do the below:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard tableView.indexPathForSelectedRow != nil else {
return
}
let selectedWord = wordArray[tableView.indexPathForSelectedRow!.row]
let destination = segue.destination as! DefinitionViewController
destination.word = selectedWord
}
DefinitionViewController:
import UIKit
class DefinitionViewController: UIViewController {
#IBOutlet weak var lbDefinition:
UILabel!
var word: String?
override func viewDidLoad() {
super.viewDidLoad()
guard word != nil else {return}
lbDefinition.text = "\((word?.wordSearch)!)"
}
}

class ViewController: UIViewController {
static var wordSearch = [string]()
}
class DefinitionViewController: UIViewController {
#IBOutlet weak var lbDefinition:UILabel!
override func viewDidLoad() {
super.viewDidLoad()
lbDefinition.text = "\(ViewController.wordSearch)"
}
}

Related

Delegate data from one UIViewController to another one

I am completely new to Swift programming and tried to delegate a single String from one ViewController to another by clicking a send button. The problem is , that it does not work ...
I guess it would be easy for you to solve this and considering that it would be very helpful wether you explain me what I did wrong. :)
Thank you a lot
import UIKit
protocol protoTYdelegate {
func didSendMessage(message: String)
}
class New: UIViewController {
#IBOutlet weak var SendButton: UIButton!
var tydelegate: protoTYdelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func SendButtonAction(_ sender: Any) {
let nachricht = "It works fine."
tydelegate?.didSendMessage(message: nachricht)
}
}
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let controller = New()
controller.tydelegate = self
}
}
extension ThankYouPage: protoTYdelegate{
func didSendMessage(message: String) {
numbersView.text = message
}
As far as I understand, this code block doesn't work but the problem is not in the code, it's actually way that you choose to send data. In iOS development, there are many ways to send data. In your case, you need to use prepareForSegue method to send data to new class, not necessary to use delegates.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "ThankYouPage") {
let vc = segue.destination as! ThankYouPage
vc.message = "Message that you want to send"
}
}
And you need to implement your ThankYouPage as:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message = ""
override func viewDidLoad() {
super.viewDidLoad()
numbersView.text = message
}
}
In addition to that, you can use didSet method to print out the message to label instead of printing it directly in viewDidLoad method. Simply:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message: String?{
didSet{
numbersView.text = message
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I hope this helps you.
#Eyup Göymen's answer is right.
I have another way, assuming that you are not using segue and you are pushing to next controller by manual-code.
So your ThankYouPage code should be like :
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func someButtonAction(_ sender: Any) { // By clicking on some, you are opening that `New` controller
let detailView = self.storyboard?.instantiateViewController(withIdentifier: "New") as! New
detailView.tydelegate = self
self.navigationController?.pushViewController(detailView, animated: true)
}
}
extension ThankYouPage: protoTYdelegate {
func didSendMessage(message: String) {
numbersView.text = message
}
}

Cannot access data passed through delegate

I am trying to understand delegate and I don't get why it says that I have used unresolved identifier 'data'.
//This is my sendingVC
import UIKit
protocol TextFieldDelegate {
func userEnteredText(text: String)
}
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate: TextFieldDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func sendButton(_ sender: AnyObject) {
if delegate != nil {
if textField.text != nil {
let data = textField.text
delegate?.userEnteredText(text: data!)
}
}
}
}
The problem is with this code below for my receivingVC I am not able to accesss data variable which should be passed by the delegate.
//This is my receivingVC
import UIKit
class SecondViewController: UIViewController, TextFieldDelegate {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func userEnteredText(text: String) {
label.text = data // Use of unresolved identifier 'data'
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "sendSegue" {
let destVC: ViewController = segue.destination as! ViewController
destVC.delegate = self
}
}
}
Update your code:
func userEnteredText(text: String) {
label.text = text
}

TableView Cell actions

I have a ViewController, with a list of data from a son file. This page run perfectly. On this page are many pub's with prices. And I want to make another scene (SecondViewController). And every time, when I push a pub from the list I want to display on another scene more information about that place. That run, but when I choose a pub the program shows the information about the first pub from the list, and when I choose another he shows the previous pub, which I choose before. And sorry my english is very bad. Please help me :D
Here is my ViewController:
import UIKit
var nev: [String] = []
var cim: [String] = []
var ar: [String] = []
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var myIndex: Int?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let url = Bundle.main.url(forResource: "pubok", withExtension: "json")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["Pubok"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
nev.append(aObject["Hely neve"] as! String)
cim.append(aObject["Cím"] as! String)
ar.append(aObject["Legolcsóbb sör"] as! String)
}
}
self.tableView.reloadData()
}
catch {
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return nev.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.nevLabel.text = nev[indexPath.row]
cell.arLabel.text = ar[indexPath.row] + "/0.5l"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! SecondViewController
vc.myIndex = myIndex
}
}
Here is my SecondViewController:
import UIKit
class SecondViewController: UIViewController {
myIndex: Int?
#IBOutlet weak var secondnevLabel: UILabel!
#IBOutlet weak var secondcimLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
secondnevLabel.text = nev[myIndex!]
secondcimLabel.text = cim[myIndex!]
}
}
And this is the TableViewCell:
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var nevLabel: UILabel!
#IBOutlet weak var arLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Instead of having the global variable myIndex, have a local variable in the second view controller. Use prepare(for segue:) in the first view controller to assign the selected row index to that variable.
ViewController:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
// etc
}
// Remove didSelectRowAt
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let row = (self.tableView.indexPathForSelectedRow as NSIndexPath?)?.row
let vc = segue.destination as! SecondViewController
vc.myIndex = row
}
SecondViewController:
class SecondViewController: UIViewController {
var myIndex: Int?
#IBOutlet weak var secondnevLabel: UILabel!
#IBOutlet weak var secondcimLabel: UILabel!
// etc

Using struct to create detail view controller from tableview

First of all, I am a beginner! So it's a bit complicated, but basically I am trying to create a separate view controller that displays information held in a struct/string with objects. I am making a directory. I have two controllers, one for the tableView (called DirectoryTableViewController) and one for the detail view (called FacultyViewController) and then I have a swift file (called People) that has manages the String.
I am eventually going to add name, phone, email and an image to the String, but for now I am just doing the names.
My problem is that it is working and I need some pointers. Thanks!!
Here is my DirectoryTableView:
import UIKit
struct peoples {
var teacherString: String!
var image: UIImage!
}
class DirectoryTableViewController: UITableViewController {
var detailViewController: DetailViewController? = nil
var array : [People]!
override func viewDidLoad() {
super.viewDidLoad()
print(array)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("directoryCell", forIndexPath: indexPath)
let person = array[indexPath.row]
cell.textLabel!.text = person.teacherString
return cell
}
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
}
Here is my NewViewController:
import UIKit
class NewViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var phoneTextField: UITextField!
#IBOutlet weak var emailTextTield: UITextField!
var array : [People] = []
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func crateObjectButton(sender: AnyObject) {
let object = People(name: nameTextField.text! , phone: phoneTextField.text!, email: emailTextTield.text!)
array.append(object)
performSegueWithIdentifier("TeacherData", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TeacherData" {
let dvc = segue.destinationViewController as? DirectoryTableViewController
dvc!.array = array
}
}
}
Here is People.swift (model):
import Foundation
class People {
var name : String
var phone: String
var email: String
init(name: String, phone: String, email: String) {
self.name = name
self.phone = phone
self.email = email
}
}
Thanks again!
As per your question , you have to make a model
import Foundation
class People {
var name : String
var phone: String
var email: String
init(name: String, phone: String, email: String) {
self.name = name
self.phone = phone
self.email = email
}
}
and make a view controller from where you gather all these details for eg: like this
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var phoneTextField: UITextField!
#IBOutlet weak var ageTextTield: UITextField!
var array : [People] = []
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func crateObjectButton(sender: AnyObject) {
let object = People(name: nameTextField.text! , phone: phoneTextField.text!, email: ageTextTield.text!)
array.append(object)
performSegueWithIdentifier("TeacherData", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TeacherData" {
let dvc = segue.destinationViewController as? TableviewController
dvc!.array = array
}
}
}
and this segue take you to the tableviewcontroller where in viewdidLoad i am printing the array of teachers.
import UIKit
class TableviewController: UITableViewController {
var array : [People]!
override func viewDidLoad() {
super.viewDidLoad()
print(array)
}
}
and you go to the deatil view controller of a selected teacher by using this method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
object = array![indexPath.row]
performSegueWithIdentifier("yourdetailviewcontrollersegue", sender: self)
}

CoreData: error: Failed to call designated initializer on NSManagedObject class

I did some research and I really don't understand what happened here.
I have this error when I select a row in a table view :
Wish[1392:37721] CoreData: error: Failed to call designated initializer on NSManagedObject class 'Wish.ProduitEntity'
(lldb)
The error is on the prepareForSegue method in ViewController class.
Thanks for the help
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var leTbleView: UITableView!
var arrayProduit = [ProduitEntity]()
var produitSelectionne : ProduitEntity? = nil
override func viewDidLoad() {
super.viewDidLoad()
self.leTbleView.dataSource = self
self.leTbleView.delegate = self
}
override func viewWillAppear(animated: Bool) {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest(entityName: "ProduitEntity")
var ilStock = [AnyObject]?()
do{
try ilStock = context.executeFetchRequest(request)
} catch _ {
}
//put info in the tableView
if ilStock != nil {
arrayProduit = ilStock as! [ProduitEntity]
}
self.leTbleView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayProduit.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel!.text = (arrayProduit[indexPath.row]).nom
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
produitSelectionne = self.arrayProduit[indexPath.row]
performSegueWithIdentifier("detailSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "detailSegue" {
let detailVC = segue.destinationViewController as! DetailViewController
detailVC.uneInstanceEntity = self.produitSelectionne!}
}
}
import UIKit
import CoreData
class DetailViewController: UIViewController {
#IBOutlet weak var titleLbl: UILabel!
#IBOutlet weak var storeLbl: UILabel!
#IBOutlet weak var imageProduit: UIImageView!
var uneInstanceEntity = ProduitEntity()
override func viewDidLoad() {
super.viewDidLoad()
self.titleLbl.text = uneInstanceEntity.nom
self.storeLbl.text = uneInstanceEntity.magasin
}
}
import UIKit
import CoreData
class ajouterProduitViewController: UIViewController {
#IBOutlet weak var modelTxtField: UITextField!
#IBOutlet weak var magasinTxtField: UITextField!
#IBOutlet weak var photoImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
//Add a new product
func sauvegardeProduit() {
let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let objetEntity = NSEntityDescription.insertNewObjectForEntityForName("ProduitEntity", inManagedObjectContext: context) as!ProduitEntity
objetEntity.nom = modelTxtField.text
objetEntity.magasin = magasinTxtField.text
//objetEntity.unVisuel = UIImageJPEGRepresentation(UIImage(named: ""), 1)
do {
try context.save()
} catch _ {
}
}
#IBAction func saveBtn(sender: AnyObject) {
sauvegardeProduit()
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func cnclBtn(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
The problem is this line:
var uneInstanceEntity = ProduitEntity()
Because you're directly creating an instance. You should't do that, you should make it optional or forced:
var uneInstanceEntity: ProduitEntity!

Resources