Эта статья была рецензирована Александром Коко . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!
Почти все приложения должны будут хранить данные той или иной формы. Возможно, вам нужно сохранить пользовательские настройки, прогресс в игре или данные в автономном режиме, чтобы ваше приложение могло работать без сетевого подключения. Разработчики имеют множество вариантов управления данными в приложениях для iOS, от Core Data до облачного хранилища, но одним из элегантных и надежных локальных хранилищ является SQLite.
В этом уроке я покажу вам, как добавить поддержку SQLite в ваше приложение. Вы можете найти окончательный исходный код на GitHub .
Начиная
Библиотека SQLite написана на C, и все запросы выполняются как вызовы функций C. Это затрудняет использование, так как вы должны знать указатели и типы данных и т. Д. Чтобы помочь, вы можете использовать оболочки Objective-C или Swift в качестве уровня адаптера.
Популярным выбором является FMDB , оболочка Objective-C для SQLite. Его легко использовать, но лично я предпочитаю не использовать жестко запрограммированные команды SQL (Structured Query Language). Для этого урока я буду использовать SQLite.swift для создания основного списка контактов.
Сначала создайте новый проект с одним представлением в Xcode (для SQLite.swift требуется Swift 2 и Xcode 7 или выше). Я создал ViewController
Main.storyboard, который выглядит следующим образом. Создайте свой собственный подобный макет или загрузите файлы раскадровки здесь .
Внизу находится TableView
Установка
Вы можете установить SQLite.swift с Carthage , CocoaPods или вручную .
Модель
Создайте новый файл / класс Swift с именем Contact.swift , он содержит три свойства и инициализатора, чтобы упростить его.
import Foundation
class Contact {
let id: Int64?
var name: String
var phone: String
var address: String
init(id: Int64) {
self.id = id
name = ""
phone = ""
address = ""
}
init(id: Int64, name: String, phone: String, address: String) {
self.id = id
self.name = name
self.phone = phone
self.address = address
}
}
id
Подключение пользовательского интерфейса
В ViewController.swift класс должен реализовывать протоколы UITableViewDelegate
UITableViewSource
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
...
}
Соедините следующие IOutlet
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var phoneTextField: UITextField!
@IBOutlet weak var addressTextField: UITextField!
@IBOutlet weak var contactsTableView: UITableView!
Теперь вам потребуется список контактов и индекс для контакта, выбранного из списка.
private var contacts = [Contact]()
private var selectedContact: Int?
Свяжите источник данных и делегат UITableView
UIViewController
Или добавив следующие строки в метод viewDidLoad()
ViewController.swift .
contactsTableView.dataSource = self
contactsTableView.delegate = self
Чтобы вставить, обновить и удалить элементы из UITableView
Первый заполнит UITextField
Yt сохранит строку, представляющую этот контакт, в таблице.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
nameTextField.text = contacts[indexPath.row].name
phoneTextField.text = contacts[indexPath.row].phone
addressTextField.text = contacts[indexPath.row].address
selectedContact = indexPath.row
}
Следующая функция сообщает UITableViewDataSource
На данный момент это будет ноль, так как массив пуст.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
Последняя функция возвращает определенный UITableViewCell
Сначала получите ячейку, используя идентификатор, затем ее дочерние представления, используя их тег. Убедитесь, что идентификаторы соответствуют вашим именам элементов.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ContactCell")!
var label: UILabel
label = cell.viewWithTag(1) as! UILabel // Name label
label.text = contacts[indexPath.row].name
label = cell.viewWithTag(2) as! UILabel // Phone label
label.text = contacts[indexPath.row].phone
return cell
}
Приложение теперь может работать, но пока нет возможности добавлять или редактировать контакты. Для этого свяжите следующие IBAction
@IBAction func addButtonClicked() {
let name = nameTextField.text ?? ""
let phone = phoneTextField.text ?? ""
let address = addressTextField.text ?? ""
let contact = Contact(id: 0, name: name, phone: phone, address: address)
contacts.append(contact)
contactsTableView.insertRowsAtIndexPaths([NSIndexPath(forRow: contacts.count-1, inSection: 0)], withRowAnimation: .Fade)
}
Здесь вы берете значения UITextField
contacts
id
Функция insertRowsAtIndexPaths()
@IBAction func updateButtonClicked() {
if selectedContact != nil {
let id = contacts[selectedContact].id!
let contact = Contact(
id: id,
name: nameTextField.text ?? "",
phone: phoneTextField.text ?? "",
address: addressTextField.text ?? "")
contacts.removeAtIndex(selectedContact!)
contacts.insert(contact, atIndex: selectedContact!)
contactsTableView.reloadData()
} else {
print("No item selected")
}
}
В этой функции вы создаете новый Contact
В настоящее время функция не проверяет, изменились ли данные.
@IBAction func deleteButtonClicked() {
if selectedContact != nil {
contacts.removeAtIndex(selectedContact)
contactsTableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: selectedContact, inSection: 0)], withRowAnimation: .Fade)
} else {
print("No item selected")
}
}
Последняя функция удаляет выбранный контакт и обновляет таблицу.
В этот момент приложение работает, но потеряет все изменения при перезапуске.
Создание базы данных
Теперь время для управления базой данных. Создайте новый файл / класс swift с именем StephencelisDB.swift и импортируйте библиотеку SQLite.
import SQLite
class StephencelisDB {
}
Сначала инициализируйте экземпляр класса, используя шаблон «Singleton». Затем объявите объект типа Connection
static let instance = StephencelisDB()
private let db: Connection?
Другие объявления — это таблица контактов и ее столбец с определенным типом.
private let contacts = Table("contacts")
private let id = Expression<Int64>("id")
private let name = Expression<String?>("name")
private let phone = Expression<String>("phone")
private let address = Expression<String>("address")
Конструктор пытается открыть соединение с базой данных, которая имеет указанное имя и путь к данным приложения, а затем создает таблицы.
private init() {
let path = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true
).first!
do {
db = try Connection("\(path)/Stephencelis.sqlite3")
} catch {
db = nil
print ("Unable to open database")
}
createTable()
}
func createTable() {
do {
try db!.run(contacts.create(ifNotExists: true) { table in
table.column(id, primaryKey: true)
table.column(name)
table.column(phone, unique: true)
table.column(address)
})
} catch {
print("Unable to create table")
}
}
Обратите внимание, что нет кода SQL для создания таблицы и столбцов. Это сила используемой оболочки. С несколькими строками кода у вас есть готовая база данных.
CRUD Операции
Для тех, кто не знаком с этим термином, «CRUD» является аббревиатурой от Create-Read-Update-Delete. Затем добавьте четыре метода в класс базы данных, которые выполняют эти операции.
func addContact(cname: String, cphone: String, caddress: String) -> Int64? {
do {
let insert = contacts.insert(name <- cname, phone <- cphone, address <- caddress)
let id = try db!.run(insert)
return id
} catch {
print("Insert failed")
return -1
}
}
Оператор <-
Метод run
id
Добавьте print(insert.asSQL())
INSERT INTO "contacts" ("name", "phone", "address") VALUES ('Deivi Taka', '+355 6X XXX XXXX', 'Tirana, Albania')
Если вы хотите провести дальнейшую отладку, вы можете вместо этого использовать метод. Метод prepare
Вы перебираете эти строки и создаете массив объектов Contact
Если эта операция завершается неудачно, возвращается пустой список.
func getContacts() -> [Contact] {
var contacts = [Contact]()
do {
for contact in try db!.prepare(self.contacts) {
contacts.append(Contact(
id: contact[id],
name: contact[name]!,
phone: contact[phone],
address: contact[address]))
}
} catch {
print("Select failed")
}
return contacts
}
Для удаления элементов найдите элемент с заданным id
func deleteContact(cid: Int64) -> Bool {
do {
let contact = contacts.filter(id == cid)
try db!.run(contact.delete())
return true
} catch {
print("Delete failed")
}
return false
}
Вы можете удалить более одного элемента одновременно, отфильтровав результаты по определенному значению столбца.
Обновление имеет похожую логику.
func updateContact(cid:Int64, newContact: Contact) -> Bool {
let contact = contacts.filter(id == cid)
do {
let update = contact.update([
name <- newContact.name,
phone <- newContact.phone,
address <- newContact.address
])
if try db!.run(update) > 0 {
return true
}
} catch {
print("Update failed: \(error)")
}
return false
}
Финальные изменения
После настройки класса управления базой данных в Viewcontroller.swift необходимо внести некоторые изменения.
Во-первых, при загрузке просмотра получить ранее сохраненные контакты.
contacts = StephencelisDB.instance.getContacts()
Методы просмотра таблицы, которые вы подготовили ранее, будут отображать сохраненные контакты без добавления чего-либо еще.
Внутри addButtonClicked
Затем обновите представление таблицы, только если метод вернул правильный id
if let id = StephencelisDB.instance.addContact(name, cphone: phone, caddress: address) {
// Add contact in the tableview
...
}
Аналогичным образом вызовите эти методы внутри updateButtonClicked
deleteButtonClicked
...
StephencelisDB.instance.updateContact(id, newContact: contact)
...
StephencelisDB.instance.deleteContact(contacts[selectedContact].id!)
...
Запустите приложение и попробуйте выполнить некоторые действия. Ниже приведены два скриншота того, как это должно выглядеть. Чтобы обновить или удалить контакт, его нужно сначала выбрать.
Любые вопросы?
SQLite является хорошим выбором для работы с локальными данными и используется многими приложениями и играми. Оболочки, такие как SQLite.swift, упрощают реализацию, избегая использования жестко закодированных SQL-запросов. Если вам нужно хранить данные в вашем приложении и вам не нужно обрабатывать более сложные параметры, тогда SQLite стоит рассмотреть.
Пусть кодекс будет с вами!