Cannot assign value of type 'ViewController' to type 'AddContactDelegate?' - ios

import UIKit
struct Contact {
var fullname: String
var contactNumber: String
}
class ViewController: UITableViewController {
var contacts = [Contact]()
#IBOutlet var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func handleAdd(_ sender: Any) {
let controller = AddContacts()
controller.delegate = self
self.present(UINavigationController(rootViewController: controller), animated: true, completion: nil)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = contacts[indexPath.row].fullname
cell.detailTextLabel?.text = contacts[indexPath.row].contactNumber
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
}
import UIKit
protocol AddContactDelegate {
func addContact(contact: Contact)
}
class AddContacts: UIViewController {
var delegate: AddContactDelegate?
#IBOutlet weak var ContactTextField: UITextField!
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func save(_ sender: Any) {
guard let fullname = nameTextField.text, nameTextField.hasText else {
print("handle error here")
return
}
guard let contactNumber = ContactTextField.text , ContactTextField.hasText else {
print("enter contact error here")
return
}
let contact = Contact(fullname: fullname, contactNumber: contactNumber)
print(contact.fullname)
print(contact.contactNumber)
delegate?.addContact(contact: contact)
}
}
in viewController: UITableViewController file it shows error like Cannot assign value of type 'ViewController' to type 'AddContactDelegate?' what should do i do to solve these error

import UIKit
struct Contact {
var fullname: String
var contactNumber: String
}
class ViewController: UITableViewController {
var contacts = [Contact]()
#IBOutlet var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func handleAdd(_ sender: Any) {
let controller = AddContacts()
controller.delegate = self
self.present(UINavigationController(rootViewController: controller), animated: true, completion: nil)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = contacts[indexPath.row].fullname
cell.detailTextLabel?.text = contacts[indexPath.row].contactNumber
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
}
// add this
extension ViewController: AddContactDelegate {
func addContact(contact: Contact) {
contacts.append(contact)
tableView.reloadData()
}
}
// thats it
import UIKit
protocol AddContactDelegate:AnyObject {
func addContact(contact: Contact)
}
class AddContacts: UIViewController {
weak var delegate: AddContactDelegate?
#IBOutlet weak var ContactTextField: UITextField!
#IBOutlet weak var nameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func save(_ sender: Any) {
guard let fullname = nameTextField.text, nameTextField.hasText else {
print("handle error here")
return
}
guard let contactNumber = ContactTextField.text , ContactTextField.hasText else {
print("enter contact error here")
return
}
let contact = Contact(fullname: fullname, contactNumber: contactNumber)
print(contact.fullname)
print(contact.contactNumber)
delegate?.addContact(contact: contact)
}
}

You must implement the protocol inside the ViewController.
Why xcode shows you the error is:
protocol ViewDelegate: AnyObject {
func didDoSomething()
}
// Which means - reference with name delegate can store objects that conform to the protocol ViewDelegate
var delegate: ViewDelegate
If you did not conform the object you are trying to store to this reference with the desired protocol, you will not be able to store that object to that reference.
You can look at protocols like contracts, if the protocol is implemented in a specific class, the class must implement the declared methods inside the protocols.
Simply implementing this protocol to your ViewController and adding the method declared in the protocol (contract) will make you achieve what you want.
class MyViewController: ViewDelegate {
func didDoSomething() {
//TODO: Logic for this method
}
}
//Will not give compile errors
let delegate: ViewDelegate = MyViewController()
Just for additional info, you can always implement a delegate in this way
class MyViewController {
//properties
}
//MARK: - ViewDelegate implementation
extension MyViewController: ViewDelegate {
func didDoSomething() {
//TODO: logic
}
}
Hope it helps.

Related

Swift TableView segue to new ViewController with wrong index path (penultimate selection)

I have a weird problem.
I have two TableViews one for showing Projects and one for showing all Team Members. With both TableViews I have the same bug.
When a user clicks on a Project/ Team Member I want to show the Details for it.
The weird thing is, when running the app and I select a Project/ Team Member for the first time, nothing is happening. When I then select another one, it shows me the details of the previous selected one.
I hope someone can help me with that.
Also a weird thing is, the entry "Sarra Fezzani" was deleted from the Firebase Database and the app was clean build, but it still shows it several times...
Since both codes are pretty similiar I will only post the Code for the ProjetTableViewController without the other files.
//
// TeamViewController.swift
// ProLabArtv2
//
import UIKit
class TeamViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var memberTableView: UITableView!
#IBOutlet weak var addTeamMember: UIButton!
var members = [TeamMember]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
setUpElements()
UserService.members(for: User.current) { (members) in
self.members = members
self.memberTableView.reloadData()
}
}
// MARK: - Element Style
func setUpElements() {
// Mark: Style the elements
Utilities.addShadowtoButton(addTeamMember)
}
func configureTableView() {
// remove separators for empty cells
memberTableView.tableFooterView = UIView()
// remove separators from cells
memberTableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMemberDetails" {
let destVC = segue.destination as! TeamMemberDetailsViewController
destVC.member = sender as? TeamMember
}
}
}
// MARK: - UITableViewDataSource
extension TeamViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let member = members[indexPath.row]
let cell = memberTableView.cellForRow(at: indexPath)
print(members)
performSegue(withIdentifier: "toMemberDetails", sender: member)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return members.count
}
// func numberOfSections(in tableView: UITableView) -> Int {
// return members.count
// }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let member = members[indexPath.row]
let cell = memberTableView.dequeueReusableCell(withIdentifier: "TeamMemberCell") as! TeamMemberCell
cell.jobLabel.text = members[indexPath.row].memberJob
cell.nameLabel.text = members[indexPath.row].memberName
return cell
}
}
// MARK: - UITableViewDelegate
extension TeamViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
import UIKit
class TeamMemberCell: UITableViewCell {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
static let height: CGFloat = 78
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
import Foundation
import UIKit
import FirebaseDatabase.FIRDataSnapshot
class TeamMember {
// Next let's add properties to store all the additional information we need. Add the following to your post class.
var key: String?
let memberName: String
let memberJob: String
let memberLanguage: String
let memberPrice: String
let memberSpecification: String
// You'll get some compiler errors for not having any initializers or default values for certain properties. Let's go ahead and fix that:
init(memberName: String, memberJob: String, memberLanguage: String, memberPrice: String, memberSpecification: String) {
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
var dictValue: [String : Any] {
return ["memberName" : memberName,
"memberJob" : memberJob,
"memberLanguage" : memberLanguage,
"memberPrice" : memberPrice,
"memberSpecification" : memberSpecification]
}
init?(snapshot: DataSnapshot) {
guard let dict = snapshot.value as? [String : Any],
let memberName = dict["memberName"] as? String,
let memberJob = dict["memberJob"] as? String,
let memberLanguage = dict["memberLanguage"] as? String,
let memberPrice = dict["memberPrice"] as? String,
let memberSpecification = dict["memberSpecification"] as? String
else { return nil }
self.key = snapshot.key
self.memberName = memberName
self.memberJob = memberJob
self.memberLanguage = memberLanguage
self.memberPrice = memberPrice
self.memberSpecification = memberSpecification
}
}
import Foundation
import FirebaseAuth.FIRUser
import FirebaseDatabase
import FirebaseUI
import FirebaseAuth
struct UserService {
static func members(for user: User, completion: #escaping ([TeamMember]) -> Void) {
let ref = Database.database().reference().child("team").child(user.uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let snapshot = snapshot.children.allObjects as? [DataSnapshot] else {
return completion([])
}
let members = snapshot.reversed().compactMap(TeamMember.init)
completion(members)
})
}
}
//
// TeamMemberDetailsViewController.swift
// ProLabArtv2
//
// Created by Manu on 09.06.20.
// Copyright © 2020 Manuel Knott. All rights reserved.
//
import UIKit
import FirebaseDatabase
import FirebaseAuth
import FirebaseStorage
class TeamMemberDetailsViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var jobLabel: UILabel!
#IBOutlet weak var specificationLabel: UILabel!
#IBOutlet weak var languageLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBOutlet weak var scoreLabel: UILabel!
#IBOutlet weak var newScoreButton: UIButton!
#IBOutlet weak var projectsPartButton: UIButton!
var member: TeamMember?
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
func setUI() {
nameLabel.text = member?.memberName
jobLabel.text = member?.memberJob
specificationLabel.text = member?.memberSpecification
languageLabel.text = member?.memberLanguage
priceLabel.text = member?.memberPrice
// scoreLabel.text = member?.
}
}
And that's the one for the ProjectViewController, where I am using a switch statement...
// HomeViewController.swift
// ProLabArtv2
//
//
import UIKit
import Kingfisher
import Foundation
import FirebaseStorage
import FirebaseDatabase
class HomeViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var addProject: UIButton!
var posts = [Post]()
var textToBeSent: String = ""
override func viewDidLoad() {
super.viewDidLoad()
UserService.posts(for: User.current) { (posts) in
self.posts = posts
self.tableView.reloadData()
}
Utilities.addShadowtoButton(addProject)
}
func configureTableView() {
// remove separators for empty cells
tableView.tableFooterView = UIView()
// remove separators from cells
tableView.separatorStyle = .none
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails" {
let destVC = segue.destination as! ShowProjectDetailsViewController
destVC.post = sender as? Post
}
}
}
// MARK: - UITableViewDataSource
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func numberOfSections(in tableView: UITableView) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = posts[indexPath.section]
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostImageCell") as! PostImageCell
let imageURL = URL(string: post.imageURL)
cell.postImageView.kf.setImage(with: imageURL)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "PostSubCell") as! PostSubCell
cell.projectName.text = post.projectTitle
return cell
default:
fatalError("Error: unexpected indexPath.")
}
}
}
// MARK: - UITableViewDelegate
extension HomeViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
let post = posts[indexPath.section]
return post.imageHeight
case 1:
return PostSubCell.height
default:
fatalError()
}
}
}
Hopefully someone can help me :)
This is one of those errors we've all made at some point, usually by not reading the autocomplete carefully.
Your code is
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath)
You've used the didDeselectRowAt rathert than didSelectRowAt method. Which means that it runs it when that row loses focus (which will be when you click on another row).
You need
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
...
You are using the wrong delegate method. Perform the segue on selecting rather than deselecting a cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = posts[indexPath.row]
performSegue(withIdentifier: "toDetails", sender: post)
}

My label.text is nil with Reusable library in swift

I'm trying to show the label with content "aaaaaaaaaaaaaaaaA". I'm using Reusable library. Although I connected IBOutlet right way, the label and imageView of cell did not show content.
This is my cell class
import UIKit
import Reusable
import SDWebImage
protocol ChooseMemberTableViewCellDelegate: AnyObject {
func addUserToGroup(forUser user: User)
}
class ChooseMemberTableViewCell: UITableViewCell, Reusable {
#IBOutlet weak var userImageView: UIImageView!
#IBOutlet weak var userNameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func setupCell(data: User) {
userNameLabel?.text = "aaaaaaaaaaaaaaaaA"
// userNameLabel?.text = "\(data.userName)"
// let url = URL(string: data.image)
// userImageView.sd_setImage(with: url ?? "", completed: nil)
}
}
This is my ViewController, which i register cell
//
// MembersViewController.swift
// Message
//
// Created by Minh Tâm on 1/9/20.
// Copyright © 2020 Minh Tâm. All rights reserved.
//
import UIKit
import Firebase
import Reusable
import Then
private enum Constants {
static let numberOfSection = 1
static let heightForRows: CGFloat = 60
}
final class ChooseMembersViewController: UIViewController {
#IBOutlet private weak var searchMembers: UISearchBar!
#IBOutlet private weak var listContacts: UITableView!
var searchUser = [User]()
private let database = Firestore.firestore()
var users = [User]()
private var currentUser = Auth.auth().currentUser
private var roomRepository = RoomRepository()
private var userRepository = UserRepository()
var groupName: String?
private var selectUserArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// userRepository.fetchUser()
configListTableView()
fetchUser()
}
func configListTableView() {
listContacts.do {
$0.register(cellType: ChooseMemberTableViewCell.self)
$0.delegate = self
$0.dataSource = self
}
}
public func fetchUser() {
database.collection("users").getDocuments(){ (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
if let snapshot = querySnapshot {
for document in snapshot.documents {
let data = document.data()
let uid = data["uid"] as? String ?? ""
if uid != self.currentUser?.uid {
let newUser = User.map(uid: uid, dictionary: data)
self.users.append(newUser)
}
}
}
self.searchUser = self.users
self.listContacts.reloadData()
}
}
}
#IBAction func handleBack(_ sender: UIButton) {
self.dismiss(animated: false)
}
#IBAction func handleDone(_ sender: UIButton) {
guard let currentUser = currentUser, let groupName = groupName else { return }
selectUserArray.append(currentUser.uid)
let time = NSNumber(value: Int(NSDate().timeIntervalSince1970))
roomRepository.updateFirebase(groupName: groupName, time: time, selectUserArray: selectUserArray)
}
}
extension ChooseMembersViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
searchUser = users
} else {
searchUser = users.filter { $0.userName.lowercased().contains(searchText.lowercased()) }
}
listContacts.reloadData()
}
}
extension ChooseMembersViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return Constants.numberOfSection
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchUser.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = listContacts.dequeueReusableCell(for: indexPath, cellType: ChooseMemberTableViewCell.self).then {
let user = searchUser[indexPath.row]
$0.setupCell(data: user)
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return Constants.heightForRows
}
}
extension ChooseMembersViewController: ChooseMemberTableViewCellDelegate {
func addUserToGroup(forUser user: User) {
let selectedUserUid = user.uid
selectUserArray.append(selectedUserUid)
}
}
Cell does not show information of label and imageView
ChooseMemberTableViewCell is correct, but I'd recommend use userNameLabel.text = "aaaaaaaaaaaaaaaaA" (not optional for userNameLabel)
If you use cell from Storyboard into your tableView - no need to register this one, the UIStoryboard already auto-register its cells. I mean you should remove this line: listContacts.register(cellType: ChooseMemberTableViewCell.self)
You should add identifier ChooseMemberTableViewCell for cell in Storyboard
This should work for cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: ChooseMemberTableViewCell = tableView.dequeueReusableCell(for: indexPath)
cell.setupCell(data: user)
.then {
let user = searchUser[indexPath.row]
$0.setupCell(data: user)
}
return cell
}
I guess that's all. I've done it and I see label with text in tableView

tableView reloadData doesn't work, delegate methods

I am trying to create new category in 1 view controller (AddCategoryViewController) and show it in table view controller (CategoryViewController). But there's an issue with reloading data.
New category item shows only after turning on and off the app, even when there is tableView.reloadData().
I tried to change the title of navigation in addButtonPressed function and the title changes immediately.
When I was using UIAlertView to add data, tableView.reloadData() worked. So I guess it's something with 2 view controllers and delegate methods?
Thanks for your help <3
show item:
import UIKit
import CoreData
class CategoryViewController: UITableViewController {
#IBOutlet weak var navigation: UINavigationItem!
var categoryArray = [Category]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
loadCategory()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categoryArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "CategoryItemCell")
cell.textLabel?.text = categoryArray[indexPath.row].name
if let randomColor = categoryArray[indexPath.row].color {
cell.textLabel?.textColor = UIColor(hex: randomColor)
}
return cell
}
// MARK: - Table view data source
#IBAction func addPressed(_ sender: UIBarButtonItem) {
let addCategoryVC = storyboard?.instantiateViewController(withIdentifier: "AddCategoryViewController") as! AddCategoryViewController
addCategoryVC.delegate = self
present(addCategoryVC, animated: true, completion: nil)
}
// MARK: - CoreData methods
func saveCategory() {
do {
try context.save()
} catch {
print("Save error: \(error)")
}
tableView.reloadData()
}
func loadCategory(with request: NSFetchRequest<Category> = Category.fetchRequest()) {
do {
categoryArray = try context.fetch(request)
} catch {
print("Load error: \(error)")
}
tableView.reloadData()
}
func addCategory(name: String, description: String) {
let newCategory = Category(context: context.self)
newCategory.name = name
newCategory.descriptionOfCategory = description
newCategory.color = UIColor.random().toHex
saveCategory()
print("name form func: \(name)")
print("description from func: \(description)")
}
}
// MARK: AddCateogry delegate methods
extension CategoryViewController: AddCategoryDelegate {
func addButtonPressed(name: String, description: String) {
addCategory(name: name, description: description)
navigation.title = "I have changed!"
}
}
Add item:
import UIKit
protocol AddCategoryDelegate {
func addButtonPressed(name: String, description: String)
}
class AddCategoryViewController: UIViewController {
var delegate : AddCategoryDelegate!
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var descriptionTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func addCategoryButtonPressed(_ sender: UIButton) {
delegate.addButtonPressed(name: nameTextField.text!, description: descriptionTextField.text!)
dismiss(animated: true, completion: nil)
}
}
You only save the category to coredata inside addCategory , but you have to add the item to the array also , or call loadCategory before tableView.reloadData() inside saveCategory

Update label text in Viewcontroller from Tableview

My question is similar to the one as here: Update label.text at runtime
I have a viewcontroller that contains a tableview with some textfields. When the user enters the quantity and amount in the perspective textfields I want to update a label outside the tableview after I press return on the final keyboard during at runtime
After doing some research I realize that this will get some in the textfieldDidEndEditing function of the textfield delegate in the cell itself but how will i access the label text from the viewcontroller so that i can update it? I will provide the code I have below.
import UIKit
import RealmSwift
class MaterialsCell: UITableViewCell, UITextFieldDelegate{
#IBOutlet weak var materialsDescription: UITextField!
#IBOutlet weak var materialsQuantity: UITextField!
#IBOutlet weak var materialsAmount: UITextField!
func saveMaterialsData() {
let saveMaterials = SPMaterialsRequest()
saveMaterials.setValue(self.materialsDescription!.text, forKey: "materialDescriptiopn")
saveMaterials.setValue(self.materialsQuantity!.text, forKey: "materialQuantity")
saveMaterials.setValue(self.materialsAmount!.text, forKey: "materialAmount")
let realm = try! Realm()
do {
try realm.write {
realm.add(saveMaterials)
print("added \(saveMaterials.materialDescription) to Realm Database")
print("added \(saveMaterials.materialQuantity) to Realm Database")
print("added \(saveMaterials.materialAmount) to Realm Database")
print("added \(saveMaterials.materialTotal) to Realm Database")
}
} catch {
print(error)
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func textFieldDidEndEditing(_ textField: UITextField) {
}
}
import UIKit
import RealmSwift
class ServiceProMaterialsController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var materialsView: UITableView!
#IBOutlet weak var materialsTotal: UILabel!
var spMaterialsRequest: Results<SPMaterialsRequest>?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "MaterialsCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? MaterialsCell
else {
fatalError("Dequed Cell is not an instance of MaterialsCell")
}
cell.materialsDescription.text = ""
cell.materialsQuantity.text = ""
cell.materialsAmount.text = ""
return cell
}
}
Create a custom delegate, implement that delegate in your viewcontroller. Pass the delegate to the cell while dequeuing the cell and calling that delegate in textFieldDidEndEditing, like :
import UIKit
import RealmSwift
protocol CustomProtocol{
func textEntered(text : String,index:Int)
}
class MaterialsCell: UITableViewCell, UITextFieldDelegate{
#IBOutlet weak var materialsDescription: UITextField!
#IBOutlet weak var materialsQuantity: UITextField!
#IBOutlet weak var materialsAmount: UITextField!
var delegate : CustomProtocol?
var index : Int?
func saveMaterialsData() {
let saveMaterials = SPMaterialsRequest()
saveMaterials.setValue(self.materialsDescription!.text, forKey: "materialDescriptiopn")
saveMaterials.setValue(self.materialsQuantity!.text, forKey: "materialQuantity")
saveMaterials.setValue(self.materialsAmount!.text, forKey: "materialAmount")
let realm = try! Realm()
do {
try realm.write {
realm.add(saveMaterials)
print("added \(saveMaterials.materialDescription) to Realm Database")
print("added \(saveMaterials.materialQuantity) to Realm Database")
print("added \(saveMaterials.materialAmount) to Realm Database")
print("added \(saveMaterials.materialTotal) to Realm Database")
}
} catch {
print(error)
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func textFieldDidEndEditing(_ textField: UITextField) {
//Usage of custom protocol
delegate?.textEntered(text : textField.text!,index:self.index!)
}
}
import UIKit
import RealmSwift
class ServiceProMaterialsController: UIViewController, UITableViewDataSource, UITableViewDelegate , CustomProtocol{
#IBOutlet weak var materialsView: UITableView!
#IBOutlet weak var materialsTotal: UILabel!
var spMaterialsRequest: Results<SPMaterialsRequest>?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "MaterialsCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? MaterialsCell
else {
fatalError("Dequed Cell is not an instance of MaterialsCell")
}
//Do 1 and 2
cell.delegate = self // 1
cell.index = indexPath.row //2
cell.materialsDescription.text = ""
cell.materialsQuantity.text = ""
cell.materialsAmount.text = ""
return cell
}
//Implementing CustomProtocol
func textEntered(text : String,index:Int){
materialsTotal.text = text
}
}

How to pass TableViewCell value into new ViewController in Swift 3.0?

I have this JSON data
move.json
{
"status":"ok",
"movement":
[
{
"refno":"REF 1",
"dtfrom":"2017-13-12"
},
{
"refno":"REF 2",
"dtfrom":"2017-13-13"
},
{
"refno":"REF 3",
"dtfrom":"2017-13-14"
},
]
}
So far, I managed to fetch the value into TableViewCell.
But my goal is to pass the value from ViewController.swift into MoveDetails.swift so the value can be display in MoveDetails.swift
And I have these four swift files. I'm having the problem on ViewController.swift and MoveDetails.swift. I'm not sure how to pass the value into new Controller.
The code as below.
ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableview: UITableView!
var move: [Move]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
let urlRequest = URLRequest(url: URL(string: "http://localhost/move.json")!)
let task = URLSession.shared.dataTask(with: urlRequest) {
(data,response,error)in
if error != nil { return }
self.move = [Move]()
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let msFromJson = json["movement"] as? [[String: AnyObject]] {
for mFromJson in msFromJson {
let ms = Move()
if let refno = mFromJson["refno"] as? String, let dtfrom = mFromJson["dtfrom"] as? String {
ms.refno = refno
ms.dtfrom = dtfrom
}
self.move?.append(ms)
}
}
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
catch let error{ print(error)}
}
task.resume()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "movementstatusCell", for: indexPath) as! MoveCell
cell.refnoLbl.text = self.move?[indexPath.item].refno
cell.dtfromLbl.text = self.move?[indexPath.item].dtfrom
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.move?.count ?? 0
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "MoveDetails") as! MoveDetails
let selectedMove = self.move?[indexPath.item]
vc.refnoString = selectedMove.refno
vc.dtfromString= selectedMove.dtfrom
self.navigationController?.pushViewController(vc, animated: true)
}
}
MoveCell.swift
import UIKit
class MoveCell: UITableViewCell {
#IBOutlet weak var dtfromLbl: UILabel!
#IBOutlet weak var refnoLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
Move.swift (NSObject)
import UIKit
class Move: NSObject {
var refno: String?
var dtfrom: String?
}
MoveDetails.swift
import UIKit
class MoveDetails: UIViewController {
#IBOutlet weak var refnoLbl: UILabel!
#IBOutlet weak var dtfromLbl: UILabel!
var refnoString: String!
var dtfromString: String!
override func viewDidLoad() {
super.viewDidLoad()
refnoString = refnoLbl.text
dtfromString = dtfromLbl.text
}
override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }
}
Appreciate if someone can help. Thanks.
You will just have to set the properties of your MoveDetails view controller. And as a suggestion
Instead of storing refnoString and dtfromString properties in MoveDetails, you could just store one property of type Move:
Cache MoveDetails view controller to reuse it
Implement viewDidAppear to update the MoveDetails outlets
So:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var detailsVC : MoveDetails?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (detailsVC == nil) {
detailsVC = self.storyboard?.instantiateViewController(withIdentifier: "MoveDetails") as! MoveDetails
}
detailsVC.move = self.move?[indexPath.item]
self.navigationController?.pushViewController(detailsVC , animated: true)
}
}
Then, override viewDidAppear in MoveDetails view controller and there you just fill in the values into the text label outlets.
class MoveDetails: UIViewController {
#IBOutlet weak var refnoLbl: UILabel!
#IBOutlet weak var dtfromLbl: UILabel!
var move:Move?
override func func viewDidAppear(_ animated: Bool) {
refnoLbl.text = move?.refno
dtfromLbl.text = move?.dtfrom
}
}
Syntax errors cause because I currently have no Xcode available to do the checking

Resources