messageCollectionView in MessageKit not being recognized - ios

I'm new to Xcode development and very new to MessageKit. I'm currently following an iOS Academy video to get the messaging section of my app working (Great series of videos by the way).
I have installed the MessageKit cocoa pod (and reinstalled it like 3 times to make sure I did it right) but yet, I can't seem to use the messagesCollectionView property.
I know it exists because first, the tutorial uses it, and second, after further investigation, ITS THE FIRST ATTRIBUTE OF THE VIEW CONTROLLER
open class MessagesViewController: UIViewController,
UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UIGestureRecognizerDelegate {
/// The `MessagesCollectionView` managed by the messages view controller object.
open var messagesCollectionView = MessagesCollectionView()
/// The `InputBarAccessoryView` used as the `inputAccessoryView` in the view controller.
open lazy var messageInputBar = InputBarAccessoryView()
when I start typing out "messagesCollectionView" there is no autocomplete and I get an error that says that it cannot be found in scope. Here is my view controller
class ChatViewController: MessagesViewController {
let currentUser = Sender(senderId: "self",displayName: "Yianni Zavaliagkos")
let otherUser = Sender(senderId: "other",displayName: "Ezra Taylor")
var messages: [MessageType] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "Chat"
messages.append(Message(sender: currentUser,
messageId: "1",
sentDate: Date().addingTimeInterval(-86400),
kind: .text("Hello World")))
messages.append(Message(sender: otherUser,
messageId: "2",
sentDate: Date().addingTimeInterval(-70000),
kind: .text("How is it going")))
//Errors on these next couple lines
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
}
and yes, I have implemented the MessegesDataSource and Layout and Display Delegates as well.
My first guess is that I installed the cocoa pod somehow incorrectly but I've tried everything and was hoping to be blessed by the StackOverflow Gods with an easy solution to this frustrating problem. Thanks!

You need to reload your collection, so put: messagesCollectionView.reloadData() to your viewDidLoad method. It works for me

Related

Setting up CVCalendar

I'm trying to implement CVCalendar with my project. I have everything in, but at the end it asks for me to connect outlets. Here is an image of the instructions:
Click here for image
I have no idea what to do as I am new to swift and xcode development. Here is the link to the github page: https://github.com/CVCalendar/CVCalendar
Any help would be appreciated, thanks!
I assume you've extended CVCalendarMenuViewDelegate and CVCalendarViewDelegate on your ViewController and implemented the delegate methods required for CVCalendar such as presentationMode and firstWeekday.
class ViewController: UIViewController {
...
}
extension ViewController: CVCalendarMenuViewDelegate {
...
}
extension ViewController: CVCalendarViewDelegate {
func presentationMode() -> CalendarMode {
return CalendarMode.monthView
}
func firstWeekday() -> Weekday {
return Weekday.monday
}
}
The last thing to do is to connect CVCalendar's menuView and calendarView objects to this class. This means that whenever an action occurs with a calendarView or menuView object the action knows to be routed to the delegate methods of your ViewController because you've attached it as an outlet.
This can be done in InterfaceBuilder by holding the control key and dragging from the menuView and calendarView to the top of the scene and then choosing the delegate to connect to, as shown in this image.
Connecting an outlet
This can also be done programmatically in your ViewController's viewDidLoad method.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
calendarView.delegate = self
menuView.delegate = self
}

updateSearchResultsForSearchController not called in iOS 9

I am trying to write a simple UITableView with a UISearchBar. I have no problem when I drag and drop a UITableViewController. Everything works! (see code below)
override func viewDidLoad() {
super.viewDidLoad()
self.searchResultsController = UISearchController(searchResultsController: nil) //initialize the search controller
self.searchResultsController.searchResultsUpdater = self //the search controller updater is this view
self.searchResultsController.dimsBackgroundDuringPresentation = false
self.searchResultsController.searchBar.sizeToFit()
self.searchResultsController.searchBar.searchBarStyle = UISearchBarStyle.Minimal
self.searchResultsController.searchBar.showsCancelButton = true
self.tableView.tableHeaderView = searchResultsController.searchBar
self.tableView.reloadData()
}
But now, for experimental purpose, I used UIViewController, and added a UITableView, no problem with showing my records in the table.
Then, added a UISearchBar from the storyboard, set its delegate to the UIViewController, but the updateSearchResultsForSearchController method is not called when the user type in something.
It's like my UISearchController has no idea there is a UISearchBar, and what ever I type in, does not evoke the updating method. Do I have to tell the UISearchController that hey this is your UISearchBar?
So here's top of my code:
class SearchViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating, UISearchBarDelegate, UISearchControllerDelegate
{
#IBOutlet weak var mySearchBar: UISearchBar!
#IBOutlet weak var myViewTable: UITableView!
let allElements = ["H", "Li", "Na", "K", "Rb", "Cs", "Fr"]
var filteredElemetns = [String]()
var searchResultsController = UISearchController() //create a new search controller
override func viewDidLoad()
{
super.viewDidLoad()
self.searchResultsController = UISearchController(searchResultsController: nil) //initialize the search controller
self.searchResultsController.searchResultsUpdater = self //the search controller updater is this view
self.searchResultsController.dimsBackgroundDuringPresentation = false
self.searchResultsController.searchBar.sizeToFit()
self.searchResultsController.searchBar.searchBarStyle = UISearchBarStyle.Minimal
self.searchResultsController.searchBar.delegate = self
//self.myViewTable.tableHeaderView = self.searchResultsController.searchBar
}
If I uncomment the last line, then I'll have two UISearchBar, which one is added by the storyboard and the other one with the last line code. The one I added, does not work, but the one at top of the myViewTable does.
Ok, I found the solution.
I used my filtering algorithm inside searchBar:textDidChange function. Then everything worked, and I don't need updateSearchResultsForSearchController function anymore. Here is my code:
func searchBar(searchBar: UISearchBar, textDidChange searchText: String)
{
print("filtering...")
self.filteredElemetns.removeAll(keepCapacity: false) //remove all the elements
let searchPredict = NSPredicate(format: "SELF CONTAINS [c] %#", self.mySearchBar.text!)
print(searchPredict)
let foundElements = (self.allElements as NSArray).filteredArrayUsingPredicate(searchPredict)
self.filteredElemetns = foundElements as! [String]
self.myViewTable.reloadData()
}
Of course, don't forget to make sure your class conforms to UISearchBarDelegate protocol.
I find this approach better than using a UITableViewController. One reason, if you search, you will find that many people have a problem with making UISearchBar the first responder. The only solution to that, I found, is calling becomeFirstResponder after a delay, which is really not a good programming approach.
But, with this approach, you can make an outlet of your UISearchBar and then easy make it the first responder in viewDidAppear.
I know some people might say no you can easily make the UISearchBar the first responder even if you use UISearchResultsController by doing something like:
self.searchResultsController.searchBar.becomeFirstResponder()
self.searchResultsController.active = true
But, believe me in iOS 8/9 it is not that simple, it won't work. Try it...

(Swift) ViewController's UI-elements can not be edited by implemented delegate method

I want to update the label in the DetailViewController everytime I selected a tableRow in the MasterViewController. To achieve this, I designed a delegate, which I have in the MasterVC
protocol TestTableViewControllerDelegate {
func selectedRow(selectedCar : Car)
}
class TestTableViewController: UITableViewController {
...
var delegate : TestTableViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = DetailViewController()
The delegate works just fine, (it is implemented correctly in the DetailVC), it can pass values from TestTableVC to DetailVC and also correctly do println(), which prints a new Car.model String to the console every time I select a row in the TTVC.
The DetailVC looks like this (shortened):
class DetailViewController: UIViewController, TestTableViewControllerDelegate {
#IBOutlet var textLabel: UILabel!
var theCar : Car? {
didSet(newCar) {
refreshUI()
}
}
override func viewDidLoad() {
super.viewDidLoad()
refreshUI()
}
func selectedRow(selectedCar : Car) {
theCar = selectedCar
refreshUI()
}
func refreshUI() {
textLabel?.text = theCar!.model
}
}
I can achieve any kind of action with my delegate, expect for refreshing the UI. I have tried numerous ways, this is my latest attempt. Before that, I tried setting the textLabel's text property directly within the delegate method, didn't work. This problem only occurs when working with the UI-elements. I know it has something to do with the view not being loaded yet, but why does my refreshUI() function not work at all?
I am still a beginner, so any tip or help would be much appreciated!
A workaround I've used is to cerate a properly in the delegate and pass the value to it instead of the UI element. When the view loads I update the label's text properly with the value of the delegates property. I would think there's a better way to do this (I'm new to programming) but this is the best soultion I've come up with so far. Will update with sample code soon.

Update a UIViewController

I use a Menu of "code4app.net" for my app and I have a problem. Source is here : click here
I update a global var in one controller:
func sendGlobalData(){
globalCurrentUser = currentUser
}
and I use it in another:
override func viewDidLoad() {
super.viewDidLoad()
setBackButton()
self.setNavigationBarItem()
userProfilePicture.profileID = globalCurrentUser.profilePictureID
userNameLabel.text = globalCurrentUser.username
}
When I click on a menu's button I need to call again this viewDidLoad function.
How can I do that?
viewDidLoad() method its automatically called during view controller lifecycle and you should not call it manually. To update your label from other view controller you should use notification center. If you are unfamiliar with it a good starting point might be this tutorial

Using A Delegate to Pass a var

I have been pulling my hair out trying to get this 'Delegate' thing to work in Swift for an App I am working on.
I have two files: CreateEvent.swift and ContactSelection.swift, where the former calls the latter.
CreateEvent's contents are:
class CreateEventViewController: UIViewController, ContactSelectionDelegate {
/...
var contactSelection: ContactSelectionViewController = ContactSelectionViewController()
override func viewDidLoad() {
super.viewDidLoad()
/...
contactSelection.delegate = self
}
func updateInvitedUsers() {
println("this finally worked")
}
func inviteButton(sender: AnyObject){
invitedLabel.text = "Invite"
invitedLabel.hidden = false
toContactSelection()
}
/...
func toContactSelection() {
let contactSelection = self.storyboard?.instantiateViewControllerWithIdentifier("ContactSelectionViewController") as ContactSelectionViewController
contactSelection.delegate = self
self.navigationController?.pushViewController(contactSelection, animated: true)
}
ContactSelection's contents are:
protocol ContactSelectionDelegate {
func updateInvitedUsers()
}
class ContactSelectionViewController: UITableViewController {
var delegate: ContactSelectionDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate?.updateInvitedUsers()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Stuff
self.delegate?.updateInvitedUsers()
}
}
What am I doing wrong? I am still new and don't fully understand this subject but after scouring the Internet I can't seem to find an answer. I use the Back button available in the Navigation Bar to return to my CreateEvent view.
var contactSelection: ContactSelectionViewController = ContactSelectionViewController()
This is instantiating a view controller directly, and the value never gets used. Since it looks like you're using storyboards, this isn't a good idea since none of the outlets will be connected and you'll get optional unwrapping crashes. You set the delegate of this view controller but that's irrelevant as it doesn't get used.
It also isn't a good idea because if you do multiple pushes you'll be reusing the same view controller and this will eventually lead to bugs as you'll have leftover state from previous uses which might give you unexpected outcomes. It's better to create a new view controller to push each time.
In your code you're making a brand new contactSelection from the storyboard and pushing it without setting the delegate.
You need to set the delegate on the instance that you're pushing onto the navigation stack.
It's also helpful to pass back a reference in the delegate method which can be used to extract values, rather than relying on a separate reference in the var like you're doing.
So, I'd do the following:
Remove the var contactSelection
Add the delegate before pushing the new contactSelection object
Change the delegate method signature to this:
protocol ContactSelectionDelegate {
func updateInvitedUsers(contactSelection:ContactSelectionViewController)
}
Change your delegate calls to this:
self.delegate?.updateInvitedUsers(self)

Resources