Realm Database Guide – Een notitie-app bouwen in Swift voor iOS

Als je video’s verkiest boven geschreven artikelen, is dit artikel een geschreven versie van een video die ik heb gemaakt. De inhoud is identiek.

Deze video is de eerste in een serie die hopelijk dient om je te leren hoe je iOS-frameworks en tools zoals Siri-sneltoetsen, CloudKit en meer kunt gebruiken. Als u een specifiek kader of functie hebt die u in deze reeks zou willen zien behandelen, voel je vrij om me te schrijven op jordanosterbergshadowsystemstech, of op Twitter @josterbe1.

Inhoudsopgave

  1. Inleiding
  2. Installatie van afhankelijkheden
  3. Het model
  4. Implementatie van Realm
  5. Conclusie

Laten we zonder verder oponthoud een blik werpen op de applicatie die we in deze serie gaan bouwen…

Inleiding

De lijst met notities
Een notitie individueel bewerken

We hebben onze lijst met notities, en als we er een aanklikken, kunnen we die lezen en bewerken, of verwijderen. Heel eenvoudig. Als je het startproject downloadt, zul je zien dat de notities niet blijven bestaan als je in en uit de NoteDetailController gaat wanneer je op de notitie “Apple Park bezoeken” tikt. Dat wil zeggen, de inhoud van de notitie wordt niet opgeslagen als je hem bewerkt.

Dat is wat we in dit artikel gaan uitbouwen, met behulp van de Realm Database. Ik gebruik Realm al zo’n twee jaar, en ik vind de eenvoud ervan opwegen tegen de kosten van het gebruik van een 3rd party library. In feite gebruik ik het in de app waar ik de meeste van mijn persoonlijke ontwikkeltijd aan besteed (zie https://countdowns.download) op zowel macOS als iOS.

Dependencies installeren

Om Realm te kunnen gebruiken, moeten we het installeren met CocoaPods. CocoaPods, als je het niet weet, CocoaPods is een dependency management tool die veel gebruikt wordt in de iOS ruimte. Als je CocoaPods nog niet op je Mac hebt geïnstalleerd, kun je het sudo gem install cocoapods commando gebruiken om te beginnen. Open nu de project map, en een Terminal venster in die map.

Typ in pod init, en dan open Podfile.

In het nieuw aangemaakte “Podfile”, moeten we wat tekst schrijven die CocoaPods laat weten welke bibliotheken je wilt installeren in je project.

Onder # Pods for NotesApp schrijft u de volgende twee regels:

pod 'Realm', '~> 3.12.0'pod 'RealmSwift', '~> 3.12.0'

Uw Podfile zou er ongeveer zo uit moeten zien nadat u deze regels hebt geschreven:

platform :ios, '12.0'target 'NotesApp' do use_frameworks! # Pods for NotesApp pod 'Realm', '~> 3.12.0' pod 'RealmSwift', '~> 3.12.0' target 'NotesAppTests' do inherit! :search_paths end target 'NotesAppUITests' do inherit! :search_paths endend

Nu we onze afhankelijkheden hebben toegevoegd, vragen we CocoaPods om ze te installeren met pod install

Dit zal enige tijd duren als u CocoaPods voor het eerst gebruikt. Maak je geen zorgen, CocoaPods is gewoon een aantal initiële componenten aan het downloaden. Dit zal niet elke keer gebeuren als u pod install.

Uw Terminal venster zal er als volgt uitzien zodra dat commando klaar is met uitvoeren:

Terminal venster

Na dit, als u de NotesApp.xcodeproj al geopend heeft, sluit u deze af. Wanneer u CocoaPods gebruikt, moet u het .xcworkspace bestand gebruiken in plaats van het standaard .xcodeproj bestand. Open het NotesApp.xcworkspace bestand en ga naar Note.swift.

Het Model

Deze klasse bevat ons Notitie model object, dat een paar basis eigenschappen bevat:

class Note { var identifier: String var content: String var lastEdited: Date init( identifier: String = UUID().uuidString, content: String, lastEdited: Date = Date()) { self.identifier = identifier self.content = content self.lastEdited = lastEdited }}

Standaard model code, niets bijzonders aan de hand hier.

We hebben ook een uitbreiding op ons Note-object in hetzelfde bestand, dat onderklasseert als protocol met de naam Writeable

extension Note: Writable { func write(dataSource: DataSource) { self.lastEdited = Date() dataSource.store(object: self) } func delete(dataSource: DataSource) { dataSource.delete(object: self) }}

Binnen de write en delete functies, ziet u dat we een DataSource eigenschap hebben. DataSource is een generiek protocol om het wijzigen van gegevens zo abstract mogelijk te maken op de hogere niveaus van onze code.

Hier vindt u de protocoldefinitie:

protocol DataSource { func store<T>(object: T) func delete<T>(object: T)}

Als u niet bekend bent met generieke functies, heeft elk van onze functies een T-parameter, wat in wezen betekent dat het elk type object kan zijn. Dit wordt niet veel gebruikt in ons project, maar het kan verder worden ontwikkeld en gebruikt om meerdere DataSources te maken met verschillende beperkingen rond welke objecten ze kunnen opslaan.

We implementeren ons DataSource protocol in NoteDataSource. Ook hier is niets bijzonders, afgezien van een kleinigheidje dat ik ter verduidelijking wil opmerken.

Wanneer we store of delete objecten, gebruiken we de volgende oproep aan NotificationCenter:

NotificationCenter.default.post(name: .noteDataChanged, object: nil)// We also have this extension of Notification.Name to make sending and receiving this notification simple.extension Notification.Name { static let noteDataChanged = Notification.Name(rawValue: "noteDataChanged")}

In wezen, wanneer een noot wordt opgeslagen of verwijderd, informeren we alle luisteraars dat onze gegevens zijn gewijzigd, zodat ze hun UI dienovereenkomstig kunnen bijwerken.

Met al onze modelbestanden en klassen uit de weg, kunnen we beginnen met de implementatie van Realm!

Realm implementeren

Er zijn drie stappen om Realm in ons project te integreren:

  1. Het Realm-object maken
  2. Verbinden tussen ons Realm-object en ons primitieve Notitie-object
  3. Beginnen met het ophalen en wijzigen van gegevens met Realm

Het Realm-object maken

Deze stap is relatief eenvoudig. Laten we een nieuw Swift-bestand met de naam RealmNote.swift maken. In RealmNote.swift importeren we het RealmSwift-framework en maken we een klassenverklaring zoals hieronder:

import RealmSwiftclass RealmNote: Object {}

We subklassen Object van Realm, zodat we RealmNote kunnen gebruiken in de databasefuncties van Realm.

Nu voegen we de drie eigenschappen toe die we in ons Notitie-model hebben:

@objc dynamic var identifier: String = ""@objc dynamic var content: String = ""@objc dynamic var lastEdited: Date = Date()

De @objc dynamic-gedeelten van onze variabelen-declaratie stellen onze eigenschappen bloot aan Objective-C, waarin veel van de iOS-lagen van Realm zijn geschreven. Hiermee kan Realm ook luisteren naar wijzigingen in onze RealmNote-objecten.

Om onze klasse af te ronden, moeten we de class func primaryKey overriden, die een optionele string (String?) met de waarde “identifier” retourneert. Hiermee wordt Realm geïnformeerd dat RealmNote’s primaire sleutel, een manier om onze objecten uniek te identificeren, is opgeslagen in de eigenschap “identifier”.

Als u deze stappen hebt voltooid, ziet uw RealmNote er als volgt uit:

class RealmNote: Object { @objc dynamic var identifier: String = "" @objc dynamic var content: String = "" @objc dynamic var lastEdited: Date = Date() override class func primaryKey() -> String? { return "identifier" }}

Dat is alles voor stap één.

Brug slaan tussen ons Realm-object en ons primitieve Note-object

We hebben twee afzonderlijke modelobjecten: Note en RealmNote. RealmNote wordt intern gebruikt als we met Realm te maken hebben, om onze modellaag los te koppelen van onze UI. Door twee afzonderlijke objecten te gebruiken, kunnen we Realm in de toekomst links laten liggen als dat nodig is.

In het RealmNote.swift-bestand maakt u een extensie van RealmNote:

extension RealmNote {}

Nu maakt u een convenience init in de extensie die als enige eigenschap een Note heeft. Hierdoor kunnen we RealmNote-objecten maken door een Note-object te gebruiken.

convenience init(note: Note) { self.init() self.identifier = note.identifier self.content = note.content self.lastEdited = note.lastEdited}

Geweldig, nu, om RealmNote.swift af te maken, maak een Note-variabele binnen de extensie die initialiseert vanuit een RealmNote:

var note: Note { return Note(realmNote: self)}

Maak je geen zorgen als Xcode je een fout geeft over de initialisator van Note, we gaan dat zo oplossen.

Wij gaan naar Note.swift, waar we de andere helft van onze bridge gaan schrijven. Deze code is in wezen hetzelfde als de uitbreiding van RealmNote.

extension Note { convenience init(realmNote: RealmNote) { self.init(identifier: realmNote.identifier, content: realmNote.content, lastEdited: realmNote.lastEdited) } var realmNote: RealmNote { return RealmNote(note: self) }}

Geweldig, dat is stap twee. We kunnen nu een RealmNote benaderen vanuit een Note, en een Note vanuit een RealmNote. Dit betekent ook dat deze code volkomen geldig is:

Note(content: "Example").realmNote.note.realmNote.note.realmNote.note.realmNote// and so on...

Grappen terzijde, laten we onze toepassing afronden met stap drie.

Begin met het ophalen en wijzigen van gegevens met Realm

Hoofd in NoteDataSource.swift, en import RealmSwift voor de klasse-verklaring. Voordat we Realm objecten wijzigen, verwijderen en opvragen, hebben we een instantie van de Realm Database nodig. Vervang NoteDataSource’s init door deze:

var realm: Realminit() { // Load our data self.realm = try! Realm()}

Dit creëert een instantie van de Realm database. In productie zou je waarschijnlijk niet de bang (!) operator willen gebruiken bij het aanmaken van de instantie, omdat je applicatie zal crashen als de database niet beschikbaar is.

Naar aanleiding van deze code bewerken we de store functie om objecten in onze database op te slaan.

Het schrijven met Realm is eenvoudig:

try? self.realm.write {}

Binnen dit codeblok kunnen we objecten in de database bijwerken. Schrijf dit:

self.realm.add(note.realmNote, update: true)

Dit creëert een nieuwe RealmNote in de database of werkt een bestaande bij als er een bestaat. Dat was het! We slaan nu objecten op in de Realm database (het aanroepen van de schrijffunctie van Notes wordt uitgevoerd in NoteDetailController.swift als je de functie wilt zien die daadwerkelijk wordt gebruikt om dit schrijven uit te voeren.)

Nu, laten we onze delete functie schrijven. Vanwege de manier waarop we onze bridge hebben geschreven (zonder Realm te raadplegen wanneer we een RealmNote maken van een Note), moeten we het object direct uit de database halen met behulp van de identifier van de notitie in plaats van de realmNote eigenschap te gebruiken.

Dit is eenvoudig:

if let realmNote = self.realm.object(ofType: RealmNote.self, forPrimaryKey: note.identifier) {}

Dit vraagt Realm om een RealmNote object op te halen uit de database, met de identifier, of primaire sleutel, van note.identifier.

Dit kan een beetje funky zijn. Om de een of andere reden crasht de applicatie als we de traditionele write functie op Realm gebruiken. Als workaround is deze code perfect geldig en voert in wezen dezelfde taak uit als write:

self.realm.beginWrite()self.realm.delete(realmNote)try? self.realm.commitWrite()

We beginnen met schrijven, we verwijderen het object en we leggen vast dat we hebben geschreven.

En daarmee hebben we een functionerende notitie-applicatie gebouwd!

Conclusie

Ik hoop dat je genoten hebt van deze tutorial over het gebruik van de Realm Database. Ik heb er veel plezier aan beleefd en ik kan niet wachten om deze serie verder te ontwikkelen en in de loop van de tijd meer functies aan onze app toe te voegen, zoals Siri-snelkoppelingen, CloudKit, en meer. Bedankt voor het lezen.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.