Use JSQMessagesViewController to create an iOS chat App-Part 1

Source: Internet
Author: User
Tags live chat

Use JSQMessagesViewController to create an iOS chat App-Part 1

In this tutorial, I will introduce how to create a simple iOS chat App (using swift and Syncano ).

In part 1 and part 2, we have created a new project, using JSQMessagesViewController as the frontend, and Syncano as the App backend.

In Part 3, we will add user logon authentication-including registration, logon, and the name of the sender that displays each message.

If you miss the previous sections, you can find them here:

Create an iOS Chat App using JSQMessagesViewController-Part 1 Create an iOS Chat App using JSQMessagesViewController-Part 21

You can start from the first part, or download the second part of the code from here.

Note that CocoaPods is used in this project. If you have not used CocoaPods, you do not know how to install it. For more information, see section 1.

Import IQKeyboardManagerSwift to add a CocoaPod

Let's add a new CocoaPod -- it is called IQKeyboardManagerSwift. Because we will create our own login/registration interface -- this will use the TextField component -- we don't want to focus on the interaction with the keyboard, so we need to use this library.

Open the terminal and enter our project path, for example:

Cd ~ /Path/to/my/project/SyncanoChat

Open Podfile:

Open Podfile

Add this sentence:

Pod 'jsqmessagesviewcontroller'

The modified Podfile eventually becomes like this:

# Uncomment this line to define a global platform for your project
# platform: ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!

target 'SyncanoChat' do
    pod 'syncano-ios'
    pod 'JSQMessagesViewController'
    pod 'IQKeyboardManagerSwift'
end

target 'SyncanoChatTests' do

end

target 'SyncanoChatUITests' do

end
Save the file, close the text editor, and enter the terminal command:

pod update

When the command is executed, open the Workspace file:

open SyncanoChat.xcworkspace

Compile the project and confirm that no errors have occurred.

Use IQKeyboardManagerSwift
Open AppDelegate.swift file and add two new imports-one for IQKeyboardManagerSwift and one for Syncano. Beginning of your file should contain these lines:

Open AppDelegate.swift and import two libraries-one is IQKeyboardManagerSwift and one is Syncano:

import syncano_ios
import IQKeyboardManagerSwift
In application (application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)-> Bool method, enable the keyboard manager and create a Syncano shared instance:

func application (application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)-> Bool {
        // Override point for customization after application launch.
        Syncano.sharedInstanceWithApiKey (syncanoApiKey, instanceName: syncanoInstanceName)
        IQKeyboardManager.sharedManager (). Enable = true
        IQKeyboardManager.sharedManager (). ShouldResignOnTouchOutside = true
        return true
    }
At this time, Xcode will report a use of unresolved identifiers error. We will solve this problem immediately.

Add settings file
To be lazy, we will use a new file to save Syncano's login credentials.

Create a new Swift file and name it Settings.

Open Settings.swift and edit the content:

let syncanoApiKey = ""
let syncanoInstanceName = ""
let syncanoChannelName = "messages"
Enter your API key and instance name here (that is, the two values you wrote in ViewController.swift).

Open ViewController.swift and delete these two sentences:

`` `swift
let syncanoChannelName = "messages"
let syncano = Syncano.sharedInstanceWithApiKey ("YOUR_API_KEY", instanceName: "YOUR_INSTANCE_NAME")





Save the file and compile the project to ensure that it can run normally.

New LoginViewController
To implement login and registration logic, we need to add a Controller. Create a new Swift file and name it LoginViewController.

Edit its content as:

import UIKit
import syncano_ios

let loginViewControllerIdentifier = "LoginViewController"

protocol LoginDelegate {
    func didSignUp ()
    func didLogin ()
}

class LoginViewController: UIViewController {
    @IBOutlet weak var emailTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!

    var delegate: LoginDelegate?
}

// MARK-UI
extension LoginViewController {
    @IBAction func loginPressed (sender: UIButton) {
        if self.areBothUsernameAndPasswordFilled () {
            self.login (self.getUsername () !, password: self.getPassword () !, finished: {error in
                if (error! = nil) {
                    // handle error
                    print ("Login, error: \ (error)")
                } else {
                    self.cleanTextFields ()
                    self.delegate? .didLogin ()
                }

            })
        }
    }

    @IBAction func signUpPressed (sender: UIButton) {
        if self.areBothUsernameAndPasswordFilled () {
            self.signUp (self.getUsername () !, password: self.getPassword () !, finished: {error in
                if (error! = nil) {
                    // handle error
                    print ("Sign Up, error: \ (error)")
                } else {
                    self.cleanTextFields ()
                    self.delegate? .didSignUp ()
                }
            })
        }
    }

    func getUsername ()-> String? {
        return self.emailTextField.text
    }

    func getPassword ()-> String? {
        return self.passwordTextField.text
    }

    func areBothUsernameAndPasswordFilled ()-> Bool {
        if let username = self.emailTextField.text, password = self.passwordTextField.text {
            if (username.characters.count> 0 && password.characters.count> 0) {
                return true
            }
        }
        return false
    }

    func cleanTextFields () {
        self.emailTextField.text = nil
        self.passwordTextField.text = nil
    }
}

// MARK-Syncano
extension LoginViewController {
    func login (username: String, password: String, finished: (NSError!)-> ()) {
        SCUser.loginWithUsername (username, password: password) {error in
            finished (error)
        }
    }

    func signUp (username: String, password: String, finished: (NSError!)-> ()) {
        SCUser.registerWithUsername (username, password: password) {error in
            finished (error)
        }
    }
}





What does this code do?

LoginDelegate protocol: Two methods are defined. According to our example, the delegate object is ViewController, so once the user logs in or creates a new account, let our main controller know through these two methods. @IBAction func loginPressed (sender: UIButton) and @IBAction func signUpPressed (sender: UIButton) methods: handle the corresponding button events. In these two methods, login and registration operations are performed, and when the operation is successful, the delegate object is notified through the protocol method. getUsername ()-> String ?, getPassword ()-> String ?, areBothUsernameAndPasswordFilled ()-> Bool and cleanTextFields () method: is 4 helper methods, used to read the input content of two TextField, clear them, check them Is empty.
Two methods for user login and registration using Syncano's SCUser class:

// MARK-Syncano
extension LoginViewController {
func login (username: String, password: String, finished: (NSError!)-> ()) {
    SCUser.loginWithUsername (username, password: password) {error in
        finished (error)
    }
}

func signUp (username: String, password: String, finished: (NSError!)-> ()) {
    SCUser.registerWithUsername (username, password: password) {error in
        finished (error)
    }
}
}
As you can see, the whole process is very simple-provide two parameters: user name, password, if the operation is unsuccessful, return an error (such as password was incorrect for login or user already exists for signup, etc.).

Modify ViewController
The new features are immediately available. Everything is ready, we only owe Dongfeng, we just need to connect everything together.

Use LoginViewController
In ViewController, we will decide whether to display LoginViewController based on user login status. First you need a LoginViewController reference. Add a new attribute:

let loginViewController = UIStoryboard (name: "Main", bundle: nil) .instantiateViewControllerWithIdentifier (loginViewControllerIdentifier) as! LoginViewController

Implement the viewDidAppear method-this method is called after the view is displayed on the screen. In this method, check whether the user has logged in. If the user has not logged in, the login interface is displayed:

    override func viewDidAppear (animated: Bool) {
        super.viewDidAppear (animated)
        self.showLoginViewControllerIfNotLoggedIn ()
    }






Because we have not implemented the self.showLoginViewControllerIfNotLoggedIn () method, we need to implement it. Add a new extension:

// MARK-Login Logic
extension ViewController: LoginDelegate {
    func didSignUp () {
        self.prepareAppForNewUser ()
        self.hideLoginViewController ()

    }

    func didLogin () {
        self.prepareAppForNewUser ()
        self.hideLoginViewController ()
    }

    func prepareAppForNewUser () {
        self.setupSenderData ()
        self.reloadAllMessages ()
    }

    func isLoggedIn ()-> Bool {
        let isLoggedIn = (SCUser.currentUser ()! = nil)
        return isLoggedIn
    }

    func logout () {
        SCUser.currentUser () ?. logout ()
    }

    func showLoginViewController () {
        self.presentViewController (self.loginViewController, animated: true) {

        }
    }

    func hideLoginViewController () {
        self.dismissViewControllerAnimated (true) {

        }
    }

    func showLoginViewControllerIfNotLoggedIn () {
        if (self.isLoggedIn () == false) {
            self.showLoginViewController ()
        }
    }

    @IBAction func logoutPressed (sender: UIBarButtonItem) {
        self.logout ()
        self.showLoginViewControllerIfNotLoggedIn ()
    }
}





What does this code do?

Implemented the LoginProtocol protocol defined above (in this way, ViewController will be notified after the user logs in or registers a new account) Several assistant methods to check whether the user is logged in (by judging whether the return value of the SCUser.currentUser () method is nil) Hidden login interface, used to handle logout (only need to call logout method on current user) two methods Modify the setup extension
There will be two errors here. We need to define two methods:

The setupSenderData () method: modify the sender information according to the user's login information (instead of the device unique identifier we used earlier reloadAllMessages () method: re-download the latest chat messages and display them to the user.
Find the setup extension in ViewController (the beginning of this extension is annotated with "// MARK-Setup") and modify it to:

// MARK-Setup
extension ViewController {
    func setup () {
        self.title = "Syncano ChatApp"
        self.setupSenderData ()
        self.channel.delegate = self
        self.channel.subscribeToChannel ()
        self.loginViewController.delegate = self
    }

    func setupSenderData () {
        let sender = (SCUser.currentUser ()! = nil)? SCUser.currentUser (). username: ""
        self.senderId = sender
        self.senderDisplayName = sender
    }
}





Here, we added the missing setupSenderData () method, in which we set senderId and senderDisplayName to the username in Syncano. In Syncano, the user name is unique, so it can be used as senderId.

In the setup () method, we set the title, set the delegate of LoginViewController to self (we have implemented a delegation protocol for self), and then call the setupSenderData () method to set the sender information.

(We removed the method of adding the test message in the first part-we no longer need it)

Finally, we have to implement the reloadAllMessages () method:

    func reloadAllMessages () {
        self.messages = []
        self.reloadMessagesView ()
        self.downloadNewestMessagesFromSyncano ()
    }





To reload chat messages, simply clear the messages array, refresh the message view again to avoid inconsistencies between the data source and the message view, and then download the latest messages from Syncano.

In the end, there was only one piece left. Find the data source extension of ViewController and add two methods:

    override func collectionView (collectionView: JSQMessagesCollectionView !, attributedTextForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!)-> NSAttributedString! {
        let data = self.collectionView (self.collectionView, messageDataForItemAtIndexPath: indexPath)
        if (self.senderDisplayName == data.senderDisplayName ()) {
            return nil
        }
        return NSAttributedString (string: data.senderDisplayName ())
    }

    override func collectionView (collectionView: JSQMessagesCollectionView !, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout !, heightForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!)-> CGFloat {
        let data = self.collectionView (self.collectionView, messageDataForItemAtIndexPath: indexPath)
        if (self.senderDisplayName == data.senderDisplayName ()) {
            return 0.0
        }
        return kJSQMessagesCollectionViewCellLabelHeightDefault
    }
The first method returns the name of the sender of each message-used to indicate who sent this message. For messages we send ourselves, we do n’t need to display this name-we know the messages we send, because these messages are always on the right (other people ’s messages are on the left), so there is no need to waste space.

The second method defines the height of the sender name Label. If we want to display the name of the sender (the sender is not his own message), we need to return a default height (return a constant in JSQMessagesViewController), otherwise return 0, Label will not be displayed.

Edit storyboard
Before you run the app, there is one last thing left:

Modify the storyboard and add a Login View Controller. Add a logout logout button on ViewController to switch users at runtime. Add navigation controller
Open the Main.storyboard file and add a navigation controller.
Drag a Navigation Controller to the storyboard. Delete the root ViewController that comes with it (via the Delete or Backspace key). Will begin Start the controller entry (blue arrow) onto the navigation controller, right-click on the navigation controller, and drag a line to the ViewController. In the pop-up menu, select root view controller.

Add logout button
vcz1yc + ho8uru / ewtMWlo6y9q8v8tcTD + 9fWuMSzySBMb2dvdXSho9TasLTFpcnP09K796Oszc / Su8z1z9 + 1vdfzsd8gT3V0bGluZSC0sL / atcQgVmlld0NvbnRyb2xsZXKjrNTata + z9rLLtaXW0NGh1PEgbG9naW5QcmVzc2VkOqOs1eLR + b7NvauwtMWlysK8 / sGsvdO1vcHLyrXP1rao0uW1xLe9t6jJz6GjPC9wPg0KPGgzIGlkPQ == "add login screen"> Add the login screen

Drag a View Controller to the storyboard. Select this View Controller and set Class to LoginViewController in the Identity panel. Set the Storyboard ID to the same value.

Then, drag 2 Text Fields and 2 Buttons to this View Controller, set the Placeholder property of the TextField and the Title property of the button.

Right click, drag a line from the Login View Controller to the two Text Fields, and connect the two TextFields to the corresponding exits.

Right-click, drag a line from the two buttons to the Login View Controller, and connect the actions of the two buttons to the corresponding methods.

Add constraints
In the storyboard, select the UI elements on LoginViewController in turn and set their constraints. Here, I align them with the nearest elements at equal intervals, and set a fixed height (using the default value).

All right! You can run the program and all its functions can be used!

You can run multiple instances of the App, log in to multiple accounts and check whether the live chat app is working properly.

There is also a bug-if you use the same account to log in on two devices, if you send a message on one of them, the message will not be displayed immediately on the other. If you can send us the solution before December 20, we will provide you with a small gift!

You can send answers, ideas or codes to email addresses [email protected]!

to sum up
You have completed the third part of this tutorial, and your app is ready to use. You can distribute it to your friends, depending on whether it is sent by you or someone else, the display of the message is quite different.

Download the code for this part here.

If you have any questions, please leave a comment in the comments below, or tweet me.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.