Delegate and DataSource not woking in MessageKit Swift IOS - ios

I'm using the MessageKit for chating when I calling the its delegate and datasource it saying (Cannot find 'messagesCollectionView' in scope) please see the code and guide me thanks.
import UIKit
import FirebaseAuth
import MessageKit
struct Message: MessageType{
var sender: SenderType
var messageId: String
var sentDate: Date
var kind: MessageKind
}
struct sender: SenderType{
var photo: String
var senderId: String
var displayName: String
}
class ChatDashboard: UIViewController {
#IBOutlet weak var lblUser: UILabel!
var userActive: String? = nil
override func viewDidLoad() {
super.viewDidLoad()
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self //not working delegate and datasource
if let userData = userActive{
self.lblUser.text = userData
}
}
override func viewDidAppear(_ animated: Bool) {
}
}

Have a look at their example project usage.
Should clear out lots of confusion.
Link: https://github.com/MessageKit/MessageKit/tree/master/Example
As for your query,
Can't find messagesCollectionView because MessagesViewControllerneeds to be extended to access that.

Related

The data I entered in the TextField does not transfer to another label

Hello guys can you help me, I have an app that has two ViewController and in the first VC I have four empty TextField and at the second VC I have four empty Labels that should receive new information and show I the label but my code doesn't work so could you help with this problem, I think something not right with my personalData
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var name: UITextField!
#IBOutlet weak var age: UITextField!
#IBOutlet weak var city: UITextField!
#IBOutlet weak var mail: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
view.addGestureRecognizer(tap)
}
#objc func edit() {
print("Edit is done")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "personalData" else { return }
guard let destination = segue.destination as? SecondViewController else { return }
destination.personalData = name.text ?? ""
destination.personalData = age.text ?? ""
destination.personalData = city.text ?? ""
destination.personalData = mail.text ?? ""
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
//////////////////////////////////////
import UIKit
class SecondViewController: UIViewController {
struct User{
}
var personalData = ""
override func viewDidLoad() {
super.viewDidLoad()
firstProfileLabel.text = personalData
secondProfileLabel.text = personalData
thirdProfileLabel.text = personalData
lastProfileLabel.text = personalData
print("SecondVC", #function)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit,
target: self,
action: #selector(edit))
}
#objc func edit() {
print("Edit is done")
}
#IBOutlet weak var firstProfileLabel: UILabel!
#IBOutlet weak var secondProfileLabel: UILabel!
#IBOutlet weak var thirdProfileLabel: UILabel!
#IBOutlet weak var lastProfileLabel: UILabel!
}
My mentor said that "The problem is with the variable personalData. The variable is of the stripe type and can store only one value.
If you want to pass values through a variable and not directly, you can create a structure, e.g. User with variables Name, Age, City, etc., and make personalData a User type and empty array."
But I don't understand how exactly I should write it in code.
Start simple. Give your second view controller separate properties for each value you want to pass:
class SecondViewController: UIViewController {
var name: String
var age: String
var city: String
var mail: String
}
Then in your first view controller's perpare(for:) method, set each of those variables separately:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "personalData" else { return }
guard let destination = segue.destination as? SecondViewController else { return }
destination.name = name.text ?? ""
destination.age = age.text ?? ""
destination.city = city.text ?? ""
destination.mail = mail.text ?? ""
}
And rewrite your second view controller's viewDidLoad method to install each property into the correct field.
Once you've got that working, you can figure out how to instead pass all the string values in a single structure.
Hint:
Create a struct called something like UserInfo:
struct UserInfo {
let name: String
let age: String
let city: String
let mail: String
}
And then give your second view controller a property of type UserInfo, and set that in prepare(for:)

Swift: using delegates to send data to another view controller

How do I use delegates to send data to another view controller and then display it in the collection view? My problem is with moving the array across using delegates.
Below is an example of what I am working on.
When I use usersList in the ThirdViewController, I get an error that says 'Unexpectedly found nil while implicitly unwrapping an Optional value'
protocol ExampleDelegate {
func delegateFunction(usersArray: Array<User>)
}
class ViewController: UIViewController {
private var model: Users = ViewController.createAccount()
var exampleDelegate: ExampleDelegate?
#IBAction func ShowUsers(_ sender: UIButton) {
let ShowUsersVC = storyboard?.instantiateViewController(identifier: "ThirdViewController") as! ThirdViewController
var userList: Array<User> = model.listOfUsers
exampleDelegate?.delegateFunction(usersArray: userList )
present(ShowUsersVC, animated: true)
}
}
class ThirdViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
var usersList: Array<User>!
override func viewDidLoad() {
super.viewDidLoad()
let GetUsersVC = storyboard?.instantiateViewController(identifier: "ViewController") as! ViewController
GetUsersVC.showMomentsDelegate = self
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension ThirdViewController: ExampleDelegate {
func delegateFunction(usersArray: Array<User>)
usersList = usersArray
}
You don't need delegates in this case. You are sending data forwards, so just do it like this:
class ViewController: UIViewController {
private var model: Users = ViewController.createAccount()
var exampleDelegate: ExampleDelegate?
#IBAction func showUsers(_ sender: UIButton) {
let showUsersVC = storyboard?.instantiateViewController(identifier: "ThirdViewController") as! ThirdViewController
var userList: Array<User> = model.listOfUsers
showUsersVC.usersList = userList /// pass the data!
present(showUsersVC, animated: true)
}
}
Also in Swift you should lowercase objects like userList, as well as functions like showUsers.

Changing Label text on main controller after modal closed swift macOS

I am using delegates to get a string value from my modal. When the modal closes I am trying to update Label text using that string. However, I am getting error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. I am not sure how to fix this. I think it's happening because the view is not yet active.
import Cocoa
class ViewControllerA: NSViewController, SomeDelegate {
#IBOutlet weak var msgLabel: NSTextField!
var s: String = "";
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func setDetails(s: String) {
self.user = s;
print("Notified", self.s) // <-- prints: Notified hello again
msgLabel.stringValue = self.s <-- DOESN'T WORK
}
func showModal() -> Void {
msgLabel.stringValue = "hello" // <--- WORKS
let cbvc: NSViewController = {
return self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! NSViewController
}()
self.presentAsModalWindow(cbvc);
}
#IBAction func onBtn(_ sender: Any) {
self.showModal();
}
}
protocol SomeDelegate {
func setDetails(s: String)
}
class ViewControllerB: NSViewController {
#IBOutlet weak var textF: NSTextField!
var delegate: SomeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let vc = ViewControllerA()
self.delegate = vc
}
#IBAction func onBtn(_ sender: Any) {
DispatchQueue.main.async {
self.delegate?.setDetails(s: self.textF.stringValue)
self.dismiss("ControllerAVC")
}
}
}
You have a number of problems.
In ViewControllerB.viewDidLoad you are assigning a new instance of ViewControllerA to the delegate property. Don't do that. Your viewDidLoad method should look like this:
override func viewDidLoad() {
super.viewDidLoad()
}
In the showModal method ViewControllerA should assign itself as the delegate on ViewControllerB before ViewControllerB it is presented.
func showModal() -> Void {
let cbvc: NSViewController = {
let vc = self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! ViewControllerB
vc.delegate = self
return vc
}()
self.presentAsModalWindow(cbvc);
}
In the setDetails method just assign the string to your text field directly:
func setDetails(s: String) {
msgLabel.stringValue = s
}

How to receive tag pressed event using tagListView?

I'm using cocoa pod of TagListView https://github.com/ElaWorkshop/TagListView. And I need to catch the tagPressed event. I know that I should implement the delegate TagListViewDelegate, but I don't know where and how. Sorry for bad eng.
Here's my code
import UIKit
import TagListView
class MoreInfoViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var tagListView: TagListView!
#IBOutlet weak var tagNameTextField: UITextField!
#IBAction func addTagButtonPressed(_ sender: UIButton) {
guard tagNameTextField.text != "" else { return }
let tagName = tagNameTextField.text!
tagNameTextField.text = ""
tagListView.addTag(tagName)
}
}
Quoting directly from the documentation,
You can implement TagListViewDelegate to receive tag pressed event:
// ...
{
// ...
tagListView.delegate = self
// ...
}
func tagPressed(title: String, tagView: TagView, sender: TagListView) {
print("Tag pressed: \(title), \(sender)")
}
Simply define your delegate and place the function within the controller and touch events should be called to this function.

iOS Swift - Properties not updating after preparing for segue

I am trying to pass a news ID of type string to the second VC and load the object based on it from Realm. When I debugged, I found that the prepare for segue is correctly setting the detailNewsVC.newsID to the primary key of my news item but the second VC is not receiving it. Any help on this?
Checks I have made:
Made sure that the detail VC identifier is correct
detailNewsVC.newsID in VC 1 is correctly setting the news ID .. This is to make sure that realm is correctly sending the newsID and it is working fine.
Changed the viewDidLoad in VC 2 to viewWillLoad..Just to make sure that second vc is not loaded before for any reason but no luck on that.
Restarted xcode
Replaced newsID in VC 2 with an actual news primary key and it's correctly pulling the related news. I think the culprit is that the VC2 property: newsID is not updating when prepare for segue is called.
First VC code for prep for segue:
extension HomeVC: UICollectionViewDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == SegueIdentifier.gotodetail.rawValue, let sendNewsID = sender as? String {
let navVC = segue.destination as? UINavigationController
let detailNewsVC = navVC?.viewControllers.first as! DetailNewsVC
detailNewsVC.newsID = sendNewsID
print("Detail News ID = \(detailNewsVC.newsID)")
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let newsID = newsArray[indexPath.row].newsId
performSegue(withIdentifier: SegueIdentifier.gotodetail.rawValue, sender: newsID)
}
}
Second VC Code:
class DetailNewsVC: UIViewController {
#IBOutlet private weak var scrollView: UIScrollView!
#IBOutlet private weak var newsTitle: UILabel!
#IBOutlet private weak var newsImage: UIImageView!
#IBOutlet private weak var newsDescription: UILabel!
var newsID = ""
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
print("News ID: \(newsID)")
guard let news = realm.object(ofType: News.self, forPrimaryKey: newsID as AnyObject) else {
print("Cannot load news")
return
}
print(news)
newsTitle.text = news.newsTitle
if let url = URL(string: news.urlToImage), let data = try? Data.init(contentsOf: url) {
newsImage.image = UIImage(data: data)
}
newsDescription.text = news.newsDescription
}
}
Move your prepare function out of the extension and put it in HomeVC. According to Apple's Swift Guide extensions cannot override existing functionality.
Extensions can add new functionality to a type, but they cannot override existing functionality.
Apple Developer Guide
It's hard to tell in which order UIKit calls the UIViewController methods, but it might be possible that viewDidLoad is getting called before you get the chance to set the value of newsID.
The following might be overkill, but it'll guarantee the views will be updated during viewDidLoad, or otherwise if newsID is set after the fact:
class DetailNewsVC: UIViewController {
#IBOutlet private weak var scrollView: UIScrollView!
#IBOutlet private weak var newsTitle: UILabel!
#IBOutlet private weak var newsImage: UIImageView!
#IBOutlet private weak var newsDescription: UILabel!
public var newsID = "" {
didSet {
updateUIForNews()
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateUIForNews()
}
private func updateUIForNews() {
guard !newsID.isEmpty else {
return
}
let realm = try! Realm()
print("News ID: \(newsID)")
guard let news = realm.object(ofType: News.self, forPrimaryKey: newsID as AnyObject) else {
print("Cannot load news")
return
}
print(news)
newsTitle.text = news.newsTitle
if let url = URL(string: news.urlToImage), let data = try? Data.init(contentsOf: url) {
newsImage.image = UIImage(data: data)
}
newsDescription.text = news.newsDescription
}
}

Resources