В связи с неожиданным решением 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 в месяц ограничений на сетевую активность нет.
Сегодня мы создадим приложения, с помощью которого пользователь сможет постить различные шутки, используя Firebase. В приложении можно будет создать свой аккаунт, используя email и пароль. Так же будет возможность постить шутки, отображаемый список шуток будет мгновенно обновляться. Когда другой пользователь постит новую шутку, список с шутками так же обновится. Еще в приложении мы добавим функцию голосования и самые смешные шутки будут получать баллы, которые они заслуживают.
Вот список функций, которые мы реализуем в приложении FirebaseJokes:
Посмотрим стартовый проект.
Сначала, откройте Main.Storyboard чтобы получить визуальное представление об приложении.
В ходе разработки приложения мы на практике проверим функциональные возможности Firebase и то что он в использовании очень прост. Мы хорошо проведете время создавая FirebaseJokes.
Перейдем на страницу Firebase и зарегистрируем аккаунт в Firebase, или войдем в уже существующий. Так же мы можем зарегистрироваться с помощью GOOGLE аккаунта. После регистрации, мы можем пройти 5ти минутное обучение, но оно предназначено для приложений написанных на JavaScript.
Чтобы просмотреть что к чему в Firebase, нажмите Manage App в My First App. Эта новая среда известна как Firebase Forge. Это крутой отладчик, и поэтому стоит пройти по нему обучение. Урок Forge поможет вам в создании ключей, значений и даже дочерних узлов с помощью символа плюс. Имеет смысл взглянуть на JSON, не так ли? Чтобы выйти из краткого обучения Forge, нажмите на панель инструментов в верхнем левом углу экрана.
Время создать FirebaseJokes. Слева My First App, нажмите на прозрачный прямоугольник, чтобы создать новое приложение. В поле APP NAME, введите “Jokes”, в APP URL введите “jokes-ваше-имя”, где “ваше-имя” это ваше собственное имя. Поле должно быть уникальным, т.к. это url для вашего приложения. Нажмите CREATE NEW APP и после Manage App.
И вот наш собственный экран Forge. При добавлении данных здесь они автоматически обновляться в нашем приложении. Также мы можем добавлять данные для приложения в вкладке Forge. Чтобы понять как работает наше приложение, с точки зрения данных, мы введем некоторые данные вручную.
Вот пример того, как выглядит объект “jokes”. Мы будем добавлять новые шутки в объект “jokes”. Также нам понадобится объект “users”. Наблюдать за тем как в Forge меняются данные, созданные приложением, интересно и в то же время — это отличная практика.
Хочу отметить, что все данные в базе данных Firebase сохраняются в виде JSON. В отличии от Parse, тут не существует никаких таблиц и записей. Когда мы добавляем данные в базу данных Firebase, они становятся ключем структуры JSON. Например, данные, которые вы только что создали, выглядят так:
Теперь, когда у вас есть базовые знания о данных которые находятся в базе данных Firebas, пора двигаться дальше.
Но перед тем, как мы перейдем к аутентификации пользователя, удалим созданные данные, также как мы будем делать это программно из приложения.
Для FirebaseJokes, мы используем аутентификацию через Email и пароль. Чтобы включить эту функцию, нажмите Login & Auth на левой панели в Forge. В Email & Password, поставьте галочку на Enable Email & Password Authentication. Сразу под нажатой ячейкой находится информация об восстановлении пароля. Также, обратите внимание на другие опции аутентификации.
Для получения base url для приложения, вернитесь на главный экран Forge. Текущий url и есть url для приложения, поэтому скопируем и вставим его в BASE_URL в Constants.swift Xcode.
Самое время добавить Firebase SDK в приложение. Перед этим нужно установить CocoaPods. Если вы его еще не установили, вы можете найти инструкции по установке CocoaPods.
Когда CocoaPods установлен, откройте терминал. Запустите следующие команды для установления Cocoapods в проект Xcode:
Затем введите следующую команду, чтобы открыть Podfile в Xcode:
Отредактируйте его:
Затем запустите следующую команду, чтобы скачать Firebase SDK:
Открываем созданный файл FirebaseJokes.xcworkspace.
Для того что бы мы могли импортировать Firebase SDK, создайте новый Objective-c File, FileType — Empty File. Назовите его Temp. При создании файла автоматически создастся файл FirebaseJokes-Bridging-Header.h. В нем пропишите такую строчку:
Удаляем Temp.m, он нам не понадобится.
Чтобы немного упростить себе жизнь, сначала мы проведём небольшую настройку в DataService.swift. В первую очередь, нам нужно несколько ссылок:
Для использования Firebase, нужно импортировать фраемворк Firebase. Класс DataService служет для взаимодействия с Firebase. Чтобы прочитать или записать данные, необходимо создать ссылку на базу данных Firebase с Firebase URL. Base URL это URL базы данных приложения. Позже мы сохраним всех пользователей и все шутки в виде дочерних узлов. Чтобы иметь доступ к дочерним узлам, можно просто задать дочернее имя (то есть пользователей) к основному URL.
Мы начнем с CreateAccountViewController.swift. Нам нужно импортировать наш фреймворк.
В методе createAccount(), мы возьмем текст, который ввел пользователь и попытаемся использовать его для создания нового пользователя. Это касается метода Firebase createUser(). Обновите существующий метод таким образом:
Если введенная информация о новом пользователе корректна, пользователь будет зарегистрирован и сможет зайти в приложение. Для любой недостающей информации будет всплывать уведомление. Для этого вставьте следующий метод в класс:
Фактически сохранение происходит в методе createNewAccount() в DataService.swift.
Для сохранения данных в базу данных Firebase, можно просто вызвать метод setValue. В коде выше, объект user сохранится в базу данных под ключом users над данным дочерним узлом uid (прим. /users/1283834/).
Кроме сохранения пользователя в базе данных Firebase, мы сохраним uid для пользователя в NSUserDefaults. Это позволит отслеживать текущего пользователя.
Прежде чем перейти дальше, импортируем Firebase в LoginViewController.swift. Так мы сможем отследить если кто-то уже входил или пытается зарегистрировать пользователя.
В методе viewDidAppear(), мы проверяем является ли наш сохраненный “uid” nil и имеет ли пользователь аккаунт. Если пользователь был авторизирован, он пропускает экран авторизации. В противном случае, он будет вынужден авторизироваться.
Метод tryLogin(), который вызывается при попытке авторизации. Обновите этот метод как показано ниже и вставьте вспомогательный метод loginErrorAlert:
Firebase имеет встроенную поддержку для аутентификации пользователя с помощью email адреса и пароля. Наш метод tryLogin() использует метод authUser(), который позволяет увидеть соответствует ли email и пароль аккаунта пользователя. Если да, мы сохраняем “uid” и попадаем внутрь приложения. Если нет, мы уведомляем пользователя, что бы повторил попытку авторизации.
Теперь приложение готово для регистрация пользователей и авторизации, пора преступить к самой реализации приложения.
Перейдем к Joke.swift и сделаем import Firebase. В нашей базе данных, шутка представлена номером ID. Это число генерируется автоматически и содержит в себе все свойства шутки. Вот они:
Мы инициализируем новый объект в методе init(), где id шутки ключ, данные шутки передаются в формате словаря.
В AddJokeViewController.swift делаем импорт Firebase. Пользователь добавляет шутку, и мы отправляем ее в наше хранилище, откуда она мгновенно отправится на все девайсы.
В методе viewDidLoad(), мы получим текущий пользовательский username, так что сможем указать автора новой шутки.
При вызове метода saveJoke() , создается словарь newJoke, который берет текст с jokeField, и устанавливает значение 0 для votes, текущего количества голосов, и для текущего имени пользователя – author. Эти значения назначают их соответствующим ids и передаются в метод createNewJoke()в DataService для сохранения.
Пропишите изменяемый параметр в классе AddJokeViewController:
Обновите метод saveJoke :
Мы используем Dictionary чтобы временно хранить данные шутки. Фактически сохранение происходит в методе createNewJoke в DataService. В DataService.swift, добавьте метод createNewJoke:
Опять же, вы можете сохранить объект с помощью метода setValue(). Когда вызывается метод childByAutoId Firebase генерирует уникальный ID для каждой шутки на основе маркера, которая гарантирует, что шутка получит уникальный ID.
Обычно это фиксируют в разделе Settings или Profile, но мы дадим пользователю возможность выйти в AddJokeViewController.swift.
Метод logout() использует Firebase метод unauth() , для деавторизации. Так же необходимо убрать пользовательский “uid” с нашего хранилища и отправить его обратно к LoginViewController.
Обновите метод logout:
Если вы не удалите пользовательский “uid”, у вас будут проблемы при входе в приложение нового пользователя.
В конечном счете, данные получаются с Firebase. Мы составляем список всех шуток в UITableView расположенные в JokesFeedTableViewController.swift. Не удивительно, что здесь мы будем импортировать Firebase.
Начнем с метода viewDidLoad(). Устанавливаем наш метод observeEventType(). Данные Firebase приходят путем добавления асинхронного слушателя к ссылке базы данных. Этот метод не вызывается во viewDidLoad() при переходе на JokesFeedTableViewController.swift, его вызывают при любых изменениях в jokes со стороны базы данных.
Метод предоставляет снимок. Используя снимок, мы можем создать ряд шуток для заполнения нашей tableView. Для шуток Firebase, мы создадим список, где новые шутки будут отображаться вверху. Поскольку Firebase распределит шутки в хронологическом порядке, мы сможем только создать ряд в обратном направлении.
Хорошо бы иметь постоянно обновляющийся массив шуток, мы помним про необходимость обновления данных в tableView чтобы мы могли увидеть их.
Остальная часть работы распределяется между tableView:cellForRowAtIndexPath: и нашей кастомной ячейкой, JokeCellTableViewCell.swift. В методе tableView:cellForRowAtIndexPath: мы отправляем шутку в метод configureCell() в JokeCellTableViewCell.swift.
Добавим метод configureCell(), в JokeCellTableViewCell.swift.
В методе voteTapped() слушатель ожидает сигнала. В этом методе сохраняются «голоса» текущего пользователя с ключом содержащим id шутки и true значение. Все это отправляется через созданный voteRef в метод configureCell().
Метод voteTapped() также ретранслирует сигнал как булевое значение в метод addSubtractVote() в Joke.swift. Значение true означает, что пользователь проголосовал за шутку; тогда как false означает, что пользователь еще не голосовал за нее.
Метод addSubtractVote(), в Joke.swift, использует булевое значение чтобы добавить или вычесть vote из joke. Затем, метод Firebase setValue() обновляет голоса по отношению к базе данных.
Теперь протестируем приложение. Создайте нового пользователя и добавьте несколько шуток. У вас будет возможность голосовать за шутки. И если вы просмотрите в панель инструментов, то увидите созданных пользователей и созданные шутки.
Мы это сделали! Это довольно забавное небольшое приложение, которое понравится пользователям благодаря его скорости отклика. Мы также получили опыт работы с Firebase.
Вы можете скачать готовый проект finished FirebaseJokes project on GitHub.
?Для IOS разработчиков существует целый мир новых возможностей с Firebase. Работа с FirebaseJokes послужит хорошей практикой, но это только начало.
Смотрите другие опции аутентификации пользователя, добавляйте новые функции к FirebaseJokes, изучайте функциональность чата, короче говоря, возможностей полно.
?Пару советов относительно хранения изображений: Firebase предоставляет относительно скромные количество памяти для их хранения, поэтому изображения лучше хранить в другом месте.
Удачи в работе работая с Firebase в ваших будущих проектах!
Среди наилучших и наиболее популярных 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 и пароль. Так же будет возможность постить шутки, отображаемый список шуток будет мгновенно обновляться. Когда другой пользователь постит новую шутку, список с шутками так же обновится. Еще в приложении мы добавим функцию голосования и самые смешные шутки будут получать баллы, которые они заслуживают.
Вот список функций, которые мы реализуем в приложении FirebaseJokes:
- Создание аккаунта
- Вход в систему с помощью email и пароля
- Выход из системы
- Пропуск регистрации для зарегистрированных пользователей
- Добавление новых шуток
- Загрузка шуток в UITableView указывая автора и количество голосов
- Возможность отдать голос за шутку
Посмотрим стартовый проект.
Сначала, откройте Main.Storyboard чтобы получить визуальное представление об приложении.
В ходе разработки приложения мы на практике проверим функциональные возможности Firebase и то что он в использовании очень прост. Мы хорошо проведете время создавая FirebaseJokes.
Время познакомиться с Firebase
Перейдем на страницу Firebase и зарегистрируем аккаунт в Firebase, или войдем в уже существующий. Так же мы можем зарегистрироваться с помощью GOOGLE аккаунта. После регистрации, мы можем пройти 5ти минутное обучение, но оно предназначено для приложений написанных на JavaScript.
Чтобы просмотреть что к чему в Firebase, нажмите Manage App в My First App. Эта новая среда известна как Firebase Forge. Это крутой отладчик, и поэтому стоит пройти по нему обучение. Урок Forge поможет вам в создании ключей, значений и даже дочерних узлов с помощью символа плюс. Имеет смысл взглянуть на JSON, не так ли? Чтобы выйти из краткого обучения Forge, нажмите на панель инструментов в верхнем левом углу экрана.
Создание нового приложения
Время создать FirebaseJokes. Слева My First App, нажмите на прозрачный прямоугольник, чтобы создать новое приложение. В поле APP NAME, введите “Jokes”, в APP URL введите “jokes-ваше-имя”, где “ваше-имя” это ваше собственное имя. Поле должно быть уникальным, т.к. это url для вашего приложения. Нажмите CREATE NEW APP и после Manage App.
И вот наш собственный экран Forge. При добавлении данных здесь они автоматически обновляться в нашем приложении. Также мы можем добавлять данные для приложения в вкладке Forge. Чтобы понять как работает наше приложение, с точки зрения данных, мы введем некоторые данные вручную.
- Нажмите «+» в ряде jokes-your-name .
- Введите “jokes” в поле name.
- Нажмите «+» в ряде с новой шуткой.
- Введите рандомное значение в поле name.
- Нажмите «+» в ряде с рандомным значением.
- Введите “jokeText” в поле name.
- Введите “What did one computer say to the other? 11001001010101” в поле value.
Вот пример того, как выглядит объект “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. Сразу под нажатой ячейкой находится информация об восстановлении пароля. Также, обратите внимание на другие опции аутентификации.
Добавление 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() обновляет голоса по отношению к базе данных.
Тестирование приложения
Теперь протестируем приложение. Создайте нового пользователя и добавьте несколько шуток. У вас будет возможность голосовать за шутки. И если вы просмотрите в панель инструментов, то увидите созданных пользователей и созданные шутки.
Подведем итог
Мы это сделали! Это довольно забавное небольшое приложение, которое понравится пользователям благодаря его скорости отклика. Мы также получили опыт работы с Firebase.
Вы можете скачать готовый проект finished FirebaseJokes project on GitHub.
?Для IOS разработчиков существует целый мир новых возможностей с Firebase. Работа с FirebaseJokes послужит хорошей практикой, но это только начало.
Смотрите другие опции аутентификации пользователя, добавляйте новые функции к FirebaseJokes, изучайте функциональность чата, короче говоря, возможностей полно.
?Пару советов относительно хранения изображений: Firebase предоставляет относительно скромные количество памяти для их хранения, поэтому изображения лучше хранить в другом месте.
Удачи в работе работая с Firebase в ваших будущих проектах!
progn
Закрытие Parse хороший стимул не связываться с вендерлок комбайнами.