В связи с неожиданным решением Facebook закрыть Parse, многое разработчики задались вопросом, что использовать вместо него. Сегодня практически невозможно представить полностью автономное приложение, которое было бы полезное всем. В связи с этим, iOS разработчики в своей работе пользуются инструментами и ресурсами, предоставленные Apple для доступа к данным. Backend-as-a-service, или сокращенно BaaS является потрясающим инструментом для разработчиков.

Среди наилучших и наиболее популярных BaaSs можно выделить Firebase от компании Google. По существу, Firebase является безусловно потрясающим в исполнении, реализации и эксплуатации. Firebase служит базой данных, которая изменяется в реальном времени и хранит данные в JSON. Любые изменения в базе данных тут же синхронизируются между всеми клиентами, или девайсами, которые используют одну и ту же базу данных. Другими словами, обновление в Firebase происходят мгновенно.

Вместе с хранилищем, Firebase также предоставляет пользовательскую аутентификацию, и поэтому все данные передаются через защищенное соединение SSL. Мы можем выбрать любую комбинацию email и пароля для аутентификации, будь то Facebook, Twitter, GitHub, Google, или что-то другое.

В добавку к iOS SDK, у Firebase есть SDK для Android и JavaScript. Все платформы могут использовать одну базу данных.
Сложно представить что Firebase со всеми этими функциями бюджетное решение.

На момент написания этой статьи, в бесплатном пакете Firebase может обрабатывать до 100 одновременных соединений. Этого вполне достаточно для работы популярного приложения. За $49 в месяц ограничений на сетевую активность нет.

Приложение FirebaseJokes


Сегодня мы создадим приложения, с помощью которого пользователь сможет постить различные шутки, используя Firebase. В приложении можно будет создать свой аккаунт, используя email и пароль. Так же будет возможность постить шутки, отображаемый список шуток будет мгновенно обновляться. Когда другой пользователь постит новую шутку, список с шутками так же обновится. Еще в приложении мы добавим функцию голосования и самые смешные шутки будут получать баллы, которые они заслуживают.

image

Вот список функций, которые мы реализуем в приложении FirebaseJokes:
  • Создание аккаунта
  • Вход в систему с помощью email и пароля
  • Выход из системы
  • Пропуск регистрации для зарегистрированных пользователей
  • Добавление новых шуток
  • Загрузка шуток в UITableView указывая автора и количество голосов
  • Возможность отдать голос за шутку

Посмотрим стартовый проект.

Сначала, откройте Main.Storyboard чтобы получить визуальное представление об приложении.

image

В ходе разработки приложения мы на практике проверим функциональные возможности Firebase и то что он в использовании очень прост. Мы хорошо проведете время создавая FirebaseJokes.

Время познакомиться с Firebase


Перейдем на страницу Firebase и зарегистрируем аккаунт в Firebase, или войдем в уже существующий. Так же мы можем зарегистрироваться с помощью GOOGLE аккаунта. После регистрации, мы можем пройти 5ти минутное обучение, но оно предназначено для приложений написанных на JavaScript.

image

Чтобы просмотреть что к чему в Firebase, нажмите Manage App в My First App. Эта новая среда известна как Firebase Forge. Это крутой отладчик, и поэтому стоит пройти по нему обучение. Урок Forge поможет вам в создании ключей, значений и даже дочерних узлов с помощью символа плюс. Имеет смысл взглянуть на JSON, не так ли? Чтобы выйти из краткого обучения Forge, нажмите на панель инструментов в верхнем левом углу экрана.

Создание нового приложения


image

Время создать FirebaseJokes. Слева My First App, нажмите на прозрачный прямоугольник, чтобы создать новое приложение. В поле APP NAME, введите “Jokes”, в APP URL введите “jokes-ваше-имя”, где “ваше-имя” это ваше собственное имя. Поле должно быть уникальным, т.к. это url для вашего приложения. Нажмите CREATE NEW APP и после Manage App.

И вот наш собственный экран Forge. При добавлении данных здесь они автоматически обновляться в нашем приложении. Также мы можем добавлять данные для приложения в вкладке Forge. Чтобы понять как работает наше приложение, с точки зрения данных, мы введем некоторые данные вручную.

  1. Нажмите «+» в ряде jokes-your-name .
  2. Введите “jokes” в поле name.
  3. Нажмите «+» в ряде с новой шуткой.
  4. Введите рандомное значение в поле name.
  5. Нажмите «+» в ряде с рандомным значением.
  6. Введите “jokeText” в поле name.
  7. Введите “What did one computer say to the other? 11001001010101” в поле value.


image

Вот пример того, как выглядит объект “jokes”. Мы будем добавлять новые шутки в объект “jokes”. Также нам понадобится объект “users”. Наблюдать за тем как в Forge меняются данные, созданные приложением, интересно и в то же время — это отличная практика.

Хочу отметить, что все данные в базе данных Firebase сохраняются в виде JSON. В отличии от Parse, тут не существует никаких таблиц и записей. Когда мы добавляем данные в базу данных Firebase, они становятся ключем структуры JSON. Например, данные, которые вы только что создали, выглядят так:

{
  "jokes" : {
    "e32e223r44" : {
      "jokeText" : "What did one computer say to the other? 11001001010101"
    }
  }
}

Теперь, когда у вас есть базовые знания о данных которые находятся в базе данных Firebas, пора двигаться дальше.
Но перед тем, как мы перейдем к аутентификации пользователя, удалим созданные данные, также как мы будем делать это программно из приложения.

Для FirebaseJokes, мы используем аутентификацию через Email и пароль. Чтобы включить эту функцию, нажмите Login & Auth на левой панели в Forge. В Email & Password, поставьте галочку на Enable Email & Password Authentication. Сразу под нажатой ячейкой находится информация об восстановлении пароля. Также, обратите внимание на другие опции аутентификации.

image

Добавление Firebase SDK


Для получения base url для приложения, вернитесь на главный экран Forge. Текущий url и есть url для приложения, поэтому скопируем и вставим его в BASE_URL в Constants.swift Xcode.

import Foundation
 
let BASE_URL = "https://jokes-matt-maher.firebaseio.com"

Самое время добавить Firebase SDK в приложение. Перед этим нужно установить CocoaPods. Если вы его еще не установили, вы можете найти инструкции по установке CocoaPods.

Когда CocoaPods установлен, откройте терминал. Запустите следующие команды для установления Cocoapods в проект Xcode:

cd <your-xcode-project-directory>
pod init

Затем введите следующую команду, чтобы открыть Podfile в Xcode:
open -a Xcode Podfile

Отредактируйте его:

platform :ios, '8.0'
use_frameworks!
 
pod 'Firebase', '>= 2.5.0'

Затем запустите следующую команду, чтобы скачать Firebase SDK:

pod install

Открываем созданный файл FirebaseJokes.xcworkspace.

Для того что бы мы могли импортировать Firebase SDK, создайте новый Objective-c File, FileType — Empty File. Назовите его Temp. При создании файла автоматически создастся файл FirebaseJokes-Bridging-Header.h. В нем пропишите такую строчку:

#import <Firebase/Firebase.h>

Удаляем Temp.m, он нам не понадобится.

Использование Firebase SDK


Чтобы немного упростить себе жизнь, сначала мы проведём небольшую настройку в DataService.swift. В первую очередь, нам нужно несколько ссылок:

import Foundation
import Firebase
 
class DataService {
    static let dataService = DataService()
    
    private var _BASE_REF = Firebase(url: "\(BASE_URL)")
    private var _USER_REF = Firebase(url: "\(BASE_URL)/users")
    private var _JOKE_REF = Firebase(url: "\(BASE_URL)/jokes")
    
    var BASE_REF: Firebase {
        return _BASE_REF
    }
    
    var USER_REF: Firebase {
        return _USER_REF
    }
    
    var CURRENT_USER_REF: Firebase {
        let userID = NSUserDefaults.standardUserDefaults().valueForKey("uid") as! String
        
        let currentUser = Firebase(url: "\(BASE_REF)").childByAppendingPath("users").childByAppendingPath(userID)
        
        return currentUser!
    }
    
    var JOKE_REF: Firebase {
        return _JOKE_REF
    }
}

Для использования Firebase, нужно импортировать фраемворк Firebase. Класс DataService служет для взаимодействия с Firebase. Чтобы прочитать или записать данные, необходимо создать ссылку на базу данных Firebase с Firebase URL. Base URL это URL базы данных приложения. Позже мы сохраним всех пользователей и все шутки в виде дочерних узлов. Чтобы иметь доступ к дочерним узлам, можно просто задать дочернее имя (то есть пользователей) к основному URL.

Создание нового пользовательского аккаунта


Мы начнем с CreateAccountViewController.swift. Нам нужно импортировать наш фреймворк.

import UIKit
import Firebase
 
class CreateAccountViewController: UIViewController {

В методе createAccount(), мы возьмем текст, который ввел пользователь и попытаемся использовать его для создания нового пользователя. Это касается метода Firebase createUser(). Обновите существующий метод таким образом:

@IBAction func createAccount(sender: AnyObject) {
    let username = usernameField.text
    let email = emailField.text
    let password = passwordField.text
    
    if username != "" && email != "" && password != "" {
        
        // Set Email and Password for the New User.
        
        DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
            
            if error != nil {
                
                // There was a problem.
                self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Try again.")
                
            } else {
                
                // Create and Login the New User with authUser
                DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
                    err, authData in
                    
                    let user = ["provider": authData.provider!, "email": email!, "username": username!]
                    
                    // Seal the deal in DataService.swift.
                    DataService.dataService.createNewAccount(authData.uid, user: user)
                })
                
                // Store the uid for future access - handy!
                NSUserDefaults.standardUserDefaults().setValue(result ["uid"], forKey: "uid")
                
                // Enter the app.
                self.performSegueWithIdentifier("NewUserLoggedIn", sender: nil)
            }
        })
        
    } else {
        signupErrorAlert("Oops!", message: "Don't forget to enter your email, password, and a username.")
    }
 
}

Если введенная информация о новом пользователе корректна, пользователь будет зарегистрирован и сможет зайти в приложение. Для любой недостающей информации будет всплывать уведомление. Для этого вставьте следующий метод в класс:

func signupErrorAlert(title: String, message: String) {
        
        // Called upon signup error to let the user know signup didn't work.
        
        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
        alert.addAction(action)
        presentViewController(alert, animated: true, completion: nil)
    }

Фактически сохранение происходит в методе createNewAccount() в DataService.swift.

func createNewAccount(uid: String, user: Dictionary<String, String>) {
        
        // A User is born.
        
        USER_REF.childByAppendingPath(uid).setValue(user)
    }

Для сохранения данных в базу данных Firebase, можно просто вызвать метод setValue. В коде выше, объект user сохранится в базу данных под ключом users над данным дочерним узлом uid (прим. /users/1283834/).

Кроме сохранения пользователя в базе данных Firebase, мы сохраним uid для пользователя в NSUserDefaults. Это позволит отслеживать текущего пользователя.

Авторизация пользователя


Прежде чем перейти дальше, импортируем Firebase в LoginViewController.swift. Так мы сможем отследить если кто-то уже входил или пытается зарегистрировать пользователя.
В методе viewDidAppear(), мы проверяем является ли наш сохраненный “uid”  nil и имеет ли пользователь аккаунт. Если пользователь был авторизирован, он пропускает экран авторизации. В противном случае, он будет вынужден авторизироваться.

override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        
        // If we have the uid stored, the user is already logger in - no need to sign in again!
        
        if NSUserDefaults.standardUserDefaults().valueForKey("uid") != nil && DataService.dataService.CURRENT_USER_REF.authData != nil {
            self.performSegueWithIdentifier("CurrentlyLoggedIn", sender: nil)
        }
    }

Метод tryLogin(), который вызывается при попытке авторизации. Обновите этот метод как показано ниже и вставьте вспомогательный метод loginErrorAlert:

@IBAction func tryLogin(sender: AnyObject) {
        
        let email = emailField.text
        let password = passwordField.text
        
        if email != "" && password != "" {
            
            // Login with the Firebase's authUser method
            
            DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: { error, authData in
                
                if error != nil {
                    print(error)
                    self.loginErrorAlert("Oops!", message: "Check your username and password.")
                } else {
                    
                    // Be sure the correct uid is stored.
                    
                    NSUserDefaults.standardUserDefaults().setValue(authData.uid, forKey: "uid")
                    
                    // Enter the app!
                    
                    self.performSegueWithIdentifier("CurrentlyLoggedIn", sender: nil)
                }
            })
            
        } else {
            
            // There was a problem
            
            loginErrorAlert("Oops!", message: "Don't forget to enter your email and password.")
        }
    }
    
    func loginErrorAlert(title: String, message: String) {
        
        // Called upon login error to let the user know login didn't work.
        
        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        let action = UIAlertAction(title: "Ok", style: .Default, handler: nil)
        alert.addAction(action)
        presentViewController(alert, animated: true, completion: nil)
    }

Firebase имеет встроенную поддержку для аутентификации пользователя с помощью email адреса и пароля. Наш метод tryLogin() использует метод authUser(), который позволяет увидеть соответствует ли email и пароль аккаунта пользователя. Если да, мы сохраняем “uid” и попадаем внутрь приложения. Если нет, мы уведомляем пользователя, что бы повторил попытку авторизации.

Теперь приложение готово для регистрация пользователей и авторизации, пора преступить к самой реализации приложения.

Объект Joke


Перейдем к Joke.swift и сделаем import Firebase. В нашей базе данных, шутка представлена номером ID. Это число генерируется автоматически и содержит в себе все свойства шутки. Вот они:
  • jokeText
  • jokeVotes
  • username (автор шутки)

Мы инициализируем новый объект в методе init(), где id шутки ключ, данные шутки передаются в формате словаря.

class Joke {
    private var _jokeRef: Firebase!
    
    private var _jokeKey: String!
    private var _jokeText: String!
    private var _jokeVotes: Int!
    private var _username: String!
    
    var jokeKey: String {
        return _jokeKey
    }
    
    var jokeText: String {
        return _jokeText
    }
    
    var jokeVotes: Int {
        return _jokeVotes
    }
    
    var username: String {
        return _username
    }
    
    // Initialize the new Joke
    
    init(key: String, dictionary: Dictionary<String, AnyObject>) {
        self._jokeKey = key
        
        // Within the Joke, or Key, the following properties are children
        
        if let votes = dictionary["votes"] as? Int {
            self._jokeVotes = votes
        }
        
        if let joke = dictionary["jokeText"] as? String {
            self._jokeText = joke
        }
        
        if let user = dictionary["author"] as? String {
            self._username = user
        } else {
            self._username = ""
        }
        
        // The above properties are assigned to their key.
        
        self._jokeRef = DataService.dataService.JOKE_REF.childByAppendingPath(self._jokeKey)
    }
}


Добавление новых шуток


В AddJokeViewController.swift делаем импорт Firebase. Пользователь добавляет шутку, и мы отправляем ее в наше хранилище, откуда она мгновенно отправится на все девайсы.

В методе viewDidLoad(), мы получим текущий пользовательский username, так что сможем указать автора новой шутки.

override func viewDidLoad() {
        super.viewDidLoad()
        
        // Get username of the current user, and set it to currentUsername, so we can add it to the Joke.
        
        DataService.dataService.CURRENT_USER_REF.observeEventType(FEventType.Value, withBlock: { snapshot in
            
            let currentUser = snapshot.value.objectForKey("username") as! String
            
            print("Username: \(currentUser)")
            self.currentUsername = currentUser
            }, withCancelBlock: { error in
                print(error.description)
        })
    }

При вызове метода saveJoke() , создается словарь newJoke, который берет текст с jokeField, и устанавливает значение 0 для votes, текущего количества голосов, и для текущего имени пользователя – author. Эти значения назначают их соответствующим ids и передаются в метод  createNewJoke()в DataService для сохранения.
Пропишите изменяемый параметр в классе AddJokeViewController:

var currentUsername = ""

Обновите метод saveJoke :

@IBAction func saveJoke(sender: AnyObject) {
        
        let jokeText = jokeField.text
        
        if jokeText != "" {
            
            // Build the new Joke. 
            // AnyObject is needed because of the votes of type Int.
            
            let newJoke: Dictionary<String, AnyObject> = [
                "jokeText": jokeText!,
                "votes": 0,
                "author": currentUsername
            ]
            
            // Send it over to DataService to seal the deal.
            
            DataService.dataService.createNewJoke(newJoke)
            
            if let navController = self.navigationController {
                navController.popViewControllerAnimated(true)
            }
        }
    }

Мы используем Dictionary чтобы временно хранить данные шутки. Фактически сохранение происходит в методе createNewJoke в DataService. В DataService.swift, добавьте метод createNewJoke:

func createNewJoke(joke: Dictionary<String, AnyObject>) {
        
        // Save the Joke
        // JOKE_REF is the parent of the new Joke: "jokes".
        // childByAutoId() saves the joke and gives it its own ID.
        
        let firebaseNewJoke = JOKE_REF.childByAutoId()
        
        // setValue() saves to Firebase.
        
        firebaseNewJoke.setValue(joke)
}

Опять же, вы можете сохранить объект с помощью метода setValue(). Когда вызывается метод childByAutoId Firebase генерирует уникальный ID для каждой шутки на основе маркера, которая гарантирует, что шутка получит уникальный ID.

Выход текущего пользователя из системы


Обычно это фиксируют в разделе Settings или Profile, но мы дадим пользователю возможность выйти в AddJokeViewController.swift.

Метод logout() использует Firebase метод unauth() , для деавторизации. Так же необходимо убрать пользовательский “uid” с нашего хранилища и отправить его обратно к LoginViewController.

Обновите метод logout:

@IBAction func logout(sender: AnyObject) {
        
        // unauth() is the logout method for the current user.
        
        DataService.dataService.CURRENT_USER_REF.unauth()
        
        // Remove the user's uid from storage.
        
        NSUserDefaults.standardUserDefaults().setValue(nil, forKey: "uid")
        
        // Head back to Login!
        
        let loginViewController = self.storyboard!.instantiateViewControllerWithIdentifier("Login")
        UIApplication.sharedApplication().keyWindow?.rootViewController = loginViewController
}

Если вы не удалите пользовательский “uid”, у вас будут проблемы при входе в приложение нового пользователя.

Отображение всех шуток на экране


В конечном счете, данные получаются с Firebase. Мы составляем список всех шуток в UITableView расположенные в JokesFeedTableViewController.swift. Не удивительно, что здесь мы будем импортировать Firebase.

Начнем с метода viewDidLoad(). Устанавливаем наш метод observeEventType(). Данные Firebase приходят путем добавления асинхронного слушателя к ссылке базы данных. Этот метод не вызывается во viewDidLoad() при переходе на JokesFeedTableViewController.swift, его вызывают при любых изменениях в jokes со стороны базы данных.

var jokes = [Joke]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // observeEventType is called whenever anything changes in the Firebase - new Jokes or Votes.
        // It's also called here in viewDidLoad().
        // It's always listening.
        
        DataService.dataService.JOKE_REF.observeEventType(.Value, withBlock: { snapshot in
            
            // The snapshot is a current look at our jokes data.
            
            print(snapshot.value)
            
            self.jokes = []
            
            if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
                
                for snap in snapshots {
                    
                    // Make our jokes array for the tableView.
                    
                    if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
                        let key = snap.key
                        let joke = Joke(key: key, dictionary: postDictionary)
                        
                        // Items are returned chronologically, but it's more fun with the newest jokes first.
                        
                        self.jokes.insert(joke, atIndex: 0)
                    }
                }
                
            }
            
            // Be sure that the tableView updates when there is new data.
            
            self.tableView.reloadData()
        })
 }

Метод предоставляет снимок. Используя снимок, мы можем создать ряд шуток для заполнения нашей tableView. Для шуток Firebase, мы создадим список, где новые шутки будут отображаться вверху. Поскольку Firebase распределит шутки в хронологическом порядке, мы сможем только создать ряд в обратном направлении.

Хорошо бы иметь постоянно обновляющийся массив шуток, мы помним про необходимость обновления данных в tableView чтобы мы могли увидеть их.

Остальная часть работы распределяется между  tableView:cellForRowAtIndexPath: и нашей кастомной ячейкой, JokeCellTableViewCell.swift. В методе tableView:cellForRowAtIndexPath: мы отправляем шутку в метод  configureCell() в JokeCellTableViewCell.swift.

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        
        return 1
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return jokes.count
    }
    
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        let joke = jokes[indexPath.row]
        
        // We are using a custom cell. 
        
        if let cell = tableView.dequeueReusableCellWithIdentifier("JokeCellTableViewCell") as? JokeCellTableViewCell {
            
            // Send the single joke to configureCell() in JokeCellTableViewCell.
            
            cell.configureCell(joke)
            
            return cell
            
        } else {
            
            return JokeCellTableViewCell()
            
        }
    }
configureCell(), in JokeCellTableViewCell.swift, is where we set the labels and listen for a vote tap.


func configureCell(joke: Joke) {
        self.joke = joke
        
        // Set the labels and textView.
        
        self.jokeText.text = joke.jokeText
        self.totalVotesLabel.text = "Total Votes: \(joke.jokeVotes)"
        self.usernameLabel.text = joke.username
        
        // Set "votes" as a child of the current user in Firebase and save the joke's key in votes as a boolean.
        
        voteRef = DataService.dataService.CURRENT_USER_REF.childByAppendingPath("votes").childByAppendingPath(joke.jokeKey)
        
        // observeSingleEventOfType() listens for the thumb to be tapped, by any user, on any device.
        
        voteRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
            
            // Set the thumb image.
            
            if let thumbsUpDown = snapshot.value as? NSNull {
                
                // Current user hasn't voted for the joke... yet.
                
                print(thumbsUpDown)
                self.thumbVoteImage.image = UIImage(named: "thumb-down")
            } else {
                
                // Current user voted for the joke!
                
                self.thumbVoteImage.image = UIImage(named: "thumb-up")
            }
        })
    }

func configureCell(joke: Joke) {
        self.joke = joke
        
        // Set the labels and textView.
        
        self.jokeText.text = joke.jokeText
        self.totalVotesLabel.text = "Total Votes: \(joke.jokeVotes)"
        self.usernameLabel.text = joke.username
        
        // Set "votes" as a child of the current user in Firebase and save the joke's key in votes as a boolean.
        
        voteRef = DataService.dataService.CURRENT_USER_REF.childByAppendingPath("votes").childByAppendingPath(joke.jokeKey)
        
        // observeSingleEventOfType() listens for the thumb to be tapped, by any user, on any device.
        
        voteRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
            
            // Set the thumb image.
            
            if let thumbsUpDown = snapshot.value as? NSNull {
                
                // Current user hasn't voted for the joke... yet.
                
                print(thumbsUpDown)
                self.thumbVoteImage.image = UIImage(named: "thumb-down")
            } else {
                
                // Current user voted for the joke!
                
                self.thumbVoteImage.image = UIImage(named: "thumb-up")
            }
        })
}

Добавим метод configureCell(), в JokeCellTableViewCell.swift.

var joke: Joke!
var voteRef: Firebase!
    
override func awakeFromNib() {
    super.awakeFromNib()
    
    // UITapGestureRecognizer is set programatically.
    
    let tap = UITapGestureRecognizer(target: self, action: "voteTapped:")
    tap.numberOfTapsRequired = 1
    thumbVoteImage.addGestureRecognizer(tap)
    thumbVoteImage.userInteractionEnabled = true
}

В методе voteTapped() слушатель ожидает сигнала. В этом методе сохраняются «голоса» текущего пользователя с ключом содержащим id шутки и true значение. Все это отправляется через созданный voteRef в метод configureCell().

func voteTapped(sender: UITapGestureRecognizer) {
        
        // observeSingleEventOfType listens for a tap by the current user.
        
        voteRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
            
            if let thumbsUpDown = snapshot.value as? NSNull {
                print(thumbsUpDown)
                self.thumbVoteImage.image = UIImage(named: "thumb-down")
                
                // addSubtractVote(), in Joke.swift, handles the vote.
                
                self.joke.addSubtractVote(true)
                
                // setValue saves the vote as true for the current user.
                // voteRef is a reference to the user's "votes" path.
                
                self.voteRef.setValue(true)
            } else {
                self.thumbVoteImage.image = UIImage(named: "thumb-up")
                self.joke.addSubtractVote(false)
                self.voteRef.removeValue()
            }
            
        })
    }

Метод voteTapped() также ретранслирует сигнал как булевое значение в метод addSubtractVote() в Joke.swift. Значение true означает, что пользователь проголосовал за шутку; тогда как false означает, что пользователь еще не голосовал за нее.

// Add or Subtract a Vote from the Joke.
    
    func addSubtractVote(addVote: Bool) {
        
        if addVote {
            _jokeVotes = _jokeVotes + 1
        } else {
            _jokeVotes = _jokeVotes - 1
        }
        
        // Save the new vote total.
        
        _jokeRef.childByAppendingPath("votes").setValue(_jokeVotes)
        
    }

Метод addSubtractVote(), в Joke.swift, использует булевое значение чтобы добавить или вычесть vote из joke. Затем, метод Firebase setValue() обновляет голоса по отношению к базе данных.

Тестирование приложения


Теперь протестируем приложение. Создайте нового пользователя и добавьте несколько шуток. У вас будет возможность голосовать за шутки. И если вы просмотрите в панель инструментов, то увидите созданных пользователей и созданные шутки.

image

Подведем итог


Мы это сделали! Это довольно забавное небольшое приложение, которое понравится пользователям благодаря его скорости отклика. Мы также получили опыт работы с Firebase.

Вы можете скачать готовый проект finished FirebaseJokes project on GitHub.

?Для IOS разработчиков существует целый мир новых возможностей с Firebase. Работа с FirebaseJokes послужит хорошей практикой, но это только начало.

Смотрите другие опции аутентификации пользователя, добавляйте новые функции к FirebaseJokes, изучайте функциональность чата, короче говоря, возможностей полно.

?Пару советов относительно хранения изображений: Firebase предоставляет относительно скромные количество памяти для их хранения, поэтому изображения лучше хранить в другом месте.

Удачи в работе работая с Firebase в ваших будущих проектах!

Комментарии (3)


  1. progn
    25.02.2016 22:48
    +3

    Закрытие Parse хороший стимул не связываться с вендерлок комбайнами.


  1. fiveze
    26.02.2016 10:56
    +1

        private var _jokeKey: String!
    
        var jokeKey: String {
            return _jokeKey
        }

    А как насчет такой конструкции (вместо той, что выше)?

    private(set) var jokeKey: String!


  1. Dalein
    06.03.2016 16:06

    Разве не должна быть пометка что это перевод?