Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
ObjectBox is a NoSQL Swift database uniquely optimized for high-performance on smartphones. Learn how to set up ObjectBox Swift and persist objects in your iOS or macOS application.
ObjectBox for Swift is a fully transactional NoSQL database and ACID compliant. Learn here how database transactions work. Also, how does multiversion concurrency work?
try store.runInTransaction {
try allUsers.forEach { user in
if (modify(user)) {
try box.put(user)
} else {
try box.remove(user)
}
}
}try allUsers.forEach { user in
modify(user) // modifies properties of given user
try box.put(user)
}try allUsers.forEach { user in
modify(user) // modifies properties of given user
}
try box.put(allUsers)Persisting objects with Entity Annotations in your iOS Swift application is easy with ObjectBox.
// objectbox: entity
class User {
var id: Id = 0
var name: String
// objectbox: transient
private var tempUsageCount: Int // not persisted
// ...
}ObjectBox Swift generates code to make it as easy to use and fun for you as possible to swiftly persist objects. In rare cases you may want adjust the code generator's work.
"$PODS_ROOT/ObjectBox/generate_sources.sh" -- --output "$PROJECT_DIR/generated/EntityInfo-TARGETNAME-iOS.generated.swift"
--model-json "$PROJECT_DIR/model-TARGETNAME-iOS.json""${PODS_ROOT}/ObjectBox/generate_sources.sh" -- --output "${PROJECT_DIR}/generated/EntityInfo.generated.swift"
--model-json "${PROJECT_DIR}/model.json""${PODS_ROOT}/ObjectBox/generate_sources.sh" -- --xcode-module JennasModule"${PODS_ROOT}/ObjectBox/generate_sources.sh" -- --visibility public"${PODS_ROOT}/ObjectBox/generate_sources.sh" -- --no-statistics/path/to/ObjectBox/Sourcery.app/Contents/MacOS/Sourcery --helpclass User: Entity {
// objectbox: id
var thisIsMyId: UInt64 = 0
// ...
}// objectbox: id = { "assignable": true }// objectbox: entity
class ExampleEntity {
var anotherID: Id = 0
// objectbox: id
var theEntityIdentifier: Id = 0 // <- this will be used
required init() {
// nothing to do here
}
}class User: Entity {
// objectbox: name = "USERNAME"
var name: String
...
}class User: Entity {
// objectbox: transient
var tempUsageCount: Int
...
}// objectbox: index
var name: String// objectbox: index = value
var name: String// objectbox: unique
var name: Stringdo {
try box.put(User("Sam Flynn"))
} catch ObjectBoxError.uniqueViolation(let message) {
// A user with that name already exists.
}Entity relations are declared using wrapper types. Learn how to form to-one and to-many relations with ObjectBox here.
ToOne is a Lazy Relation ProxyToManyclass Customer: Entity {
var id: Id = 0
// ...
}
class Order: Entity {
var id: Id = 0
var customer: ToOne<Customer> = nil
// ...
}let store = ...
// Illustrate that initially, nothing did exist
assert(try store.box(for: Customer.self).isEmpty())
assert(try store.box(for: Order.self).isEmpty())
let customer = Customer()
let order = Order()
order.customer.target = customer
let orderId = try store.box(for: Order.self).put(order) // puts order and customer
// Verify the `put` was called for the relation target as well
assert(try store.box(for: Customer.self).count() == 1)
assert(try store.box(for: Order.self).count() == 1)anOrder.customer.target = nil
// ... or ...
anOrder.customer.targetId = nil
// ... are both equivalent to:
anOrder.customer = nil
// ... whis is a short version of:
anOrder.customer = ToOne<Customer>(target: nil)class Customer: Entity {
var id: Id = 0
// objectbox: backlink = "customer"
var orders: ToMany<Order> = nil
// ...
}
class Order: Entity {
var id: Id = 0
var customer: ToOne<Customer> = nil
// ...
}// Store two new orders for a new customer
let customer = Customer()
let order1 = Order(customer: customer)
let order2 = Order(customer: customer)
try store.box(for: Order.self).put([order1, order2])
// ID of customer was also set by put()
assert(customer.id != 0)
// Backlink: customer has two orders
assert(try store.box(for: Customer.self).get(customer.id).orders.count() == 2)let orders = Array(customer.orders)let newOrder = Order(summary: "Shoes")
// try orderBox.put(newOrder) // ObjectBox Swift 1.4+ does not need this
aCustomer.orders.replace([newOrder, oldOrder])
try aCustomer.orders.applyToDb()// You cannot set `aCustomer.orders = nil`, so:
aCustomer.orders.replace([])
try aCustomer.orders.applyToDb()class Teacher: Entity {
var id: Id = 0
...
}
class Student: Entity {
var id: Id = 0
var ToMany<Teacher> teachers = nil
...
}let teacher1 = Teacher()
let teacher2 = Teacher()
let student1 = Student()
let student2 = Student()
// try store.box(for: Teacher.self).put([teacher1, teacher2])
try store.box(for: Student.self).put([student1, student2])
student1.teachers.append(teacher1)
student1.teachers.append(teacher2)
student2.teachers.append(teacher2)
try student1.teachers.applyToDb()
try student2.teachers.applyToDb()var student1 = try boxStore.box(for: Student.self).get(student1.id)
for (let teacher in student1.teachers) {
...
}student1.teachers.remove(at: 0)
try student1.teachers.applyToDb()class Teacher: Entity {
var id: Id = 0
// objectbox: backlink = "teachers"
var students: ToMany<Student> = nil
...
}
class Student: Entity {
var id: Id = 0
var teachers: ToMany<Teacher> = nil
...
}// Insert a student
try box.put(&student)
// To update its ToMany (applies to ToOne as well), get a fresh copy
let updatableStudent = try box.get(student.id)
updatableStudent.teachers.append(teacher)
try updatableStudent.teachers.applyToDb()class TreeNode: Entity {
var id: Id = 0
var parent: ToOne<TreeNode> = nil
// objectbox: backlink = "parent"
var children: ToMany<TreeNode> = nil
}let parent = entity.parent.target
let children = Array(entity.children)


"${PROJECT_DIR}/ObjectBox/generate_sources.sh""${PROJECT_DIR}/../external/ObjectBox/generate_sources.sh"The ObjectBox Swift database supports building Queries using a query builder. Learn all about Query syntax and how to get to entities and their property values by filtering for specific criteria.
let query: Query<Person> = try personBox.query {
Person.name.startsWith("Andrea")
}.build()
let allAndreas: [Person] = try query.find()Property<E, Date, R> exposes methods for dates, like isBetween(_:and:)default// objectbox: convertlet query: Query<Person> = try personBox.query {
Person.firstName.startsWith("Ste")
&& Person.lastName.startsWith("Jo")
}.build()
let maybeSteveJobs = try query.find()let query: Query<Person> = try personBox.query {
(Person.firstName.contains("Santa") || Person.age > 100)
&& Person.lastName.isEqual(to: "Claus", caseSensitive: true)
}.build()
let oldClauses = try query.find()let query = try userBox.query { User.firstName == "Joe" }
.ordered(by: User.lastName) // in ascending order, ignoring case
.build()let query = try userBox.query { User.firstName == "Joe" }
.ordered(by: User.lastName, flags: [.descending, .caseSensitive])
.build()let query = try personBox.query {
Person.age > 10
&& Person.age < 50
}.build()
query.setParameter(Person.age, to: 25) // did this affect "<" or ">" ?let query = try personBox.query {
"MinAge" .= Person.age > 10
&& "MaxAge" .= Person.age < 50
}.build()
query.setParameter("MinAge", to: 25)let query: Query<Person> = try personBox.query { Person.firstName.startsWith("S") }.build()
let agePropertyQuery: PropertyQuery<Person, Int> = query.property(Person.age)let query: Query<Person> = try personBox.query().build()
let agePropertyQuery: PropertyQuery<Person, Int> = query.property(Person.age)
let maxAge: Int = try agePropertyQuery.max()
let minAge: Int = try agePropertyQuery.min()
let averageAge: Double = try agePropertyQuery.average()let query: Query<Person> = try personBox.query { Person.firstName == "Steve" }.build()
let steveLastNamePQ: PropertyQuery<Person, String> = query.property(Person.lastName)
let allOfStevesLastNames: [String] = try steveLastNamePQ.findStrings()
// if allOfStevesLastNames.contains("Jobs") { ... }let names: [String] = try personBox.query().build()
.property(Person.firstName)
.distinct(caseSensitiveCompare: false)
.findStrings()do {
let singleNameResult: String = try personBox.query { Person.age > 999 }.build()
.property(Person.firstName)
.findUniqueString()
} catch ObjectBoxError.uniqueViolation(let message) {
print("Found more than one item! \(message)")
}
guard let singleNameResult = singleNameResult else {
fatalError("No result found at all.")
}let sallysOrders = try orderBox.query{
Order.date.isAfter(thisMorning)
}.link(Order.customer) {
Customer.name == "Sally Sparrow"
}.build().find()class Person: Entity {
var id: Id = 0
var firstName: String
var lastName: String
var age: Int
init(firstName: String, lastName: String, age: Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
// ...
}extension Person {
static var id: Property<Person, Id, Void> { /* ... */ }
static var firstName: Property<Person, String, Void> { /* ... */ }
static var lastName: Property<Person, String, Void> { /* ... */ }
static var age: Property<Person, Int, Void> { /* ... */ }
}Int8, UInt8
Int16, UInt16
Int32, UInt32
Int64, Int, UInt64, UInt
Float, Double
Data, [UInt8]
String
Dateenum TestEnum: Int {
case unknown = 0
case first = 100
case second = 200
case third = 300
}
class EnumEntity: Entity {
var id: Id = 0
// objectbox: convert = { "default": ".unknown" }
var custom: TestEnum
}class RoleConverter {
static func convert(_ enumerated: Role) -> Int {
return enumerated.rawValue
}
static func convert(_ num: Int?) -> Role {
guard let num = num else { return Role.default }
return TestEnum(rawValue: num) ?? Role.default
}
}
enum Role: Int {
case default = 0
case author = 1
case admin = 2
}
class User: Entity, CustomDebugStringConvertible {
var id: Id = 0
// objectbox: convert = { "dbType": "Int", "converter": "RoleConverter" }
var role = Role.default
}
class Document {
var id: Id = 0
var userNames: [String] // ObjectBox doesn't know how to store this
}class Document {
var id: Id = 0
var users: ToMany<User>
}
class User {
var id: Id = 0
var document: ToOne<Document> = nil
var name: String
}Learn how to use ObjectBox NoSQL DB to persist data with swift for an Offline-first iOS app experience. ObjectBox performs well on all CRUD operations and is fully ACID compliant.
import ObjectBox
// objectbox: entity
class Person {
var id: Id = 0
var firstName: String = ""
var lastName: String = ""
init() {} // Used by ObjectBox
init(id: Id = 0, firstName: String, lastName: String) {
self.id = id
self.firstName = firstName
self.lastName = lastName
}
}swift package plugin --allow-writing-to-package-directory --allow-network-connections all objectbox-generator --target <target-name>swift package describelet store = try Store(directoryPath: "/Users/jenna/Documents/mydatabase/")let databaseName = "notes"
let appSupport = try FileManager.default.url(for: .applicationSupportDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
.appendingPathComponent(Bundle.main.bundleIdentifier!)
let directory = appSupport.appendingPathComponent(databaseName)
try? FileManager.default.createDirectory(at: directory,
withIntermediateDirectories: true,
attributes: nil)
let store = try Store(directoryPath: directory.path)let exampleEntityBox = store.box(for: ExampleEntity.self)
// Similarly:
let personBox = store.box(for: Person.self)
let noteBox: Box<Note> = store.box()// let's start with an empty box
assert(try exampleEntityBox.isEmpty())
let exampleEntity = ExampleEntity()
assert(exampleEntity.id.value == 0)
let newID = try exampleEntityBox.put(exampleEntity)
// Change of ID with the `put`:
assert(exampleEntity.id.value != 0)
assert(exampleEntity.id == newID)
// Check the Box contents did indeed change:
assert(try exampleEntityBox.count() == 1)
assert(try exampleEntityBox.all().first?.id == newID)
// Getting to a specific object
guard let foundEntity = try exampleEntityBox.get(newID)
else { fatalError("Object should be in the box") }
assert(exampleEntity.id == foundEntity.id)
// Cleaning up
try exampleEntityBox.removeAll()
assert(try exampleEntityBox.count() == 0)// objectbox: entity
struct Author {
var id: Id // Do not initialize the ID to 0 for structs.
var name: String
var age: Int
}
let exampleEntityBox = store.box(for: Author.self)
var exampleEntity = Author(id: 0, name: "Nnedi Okorafor", age: 45)
// Put the struct and update the ID:
try exampleEntityBox.put(&exampleEntity)
assert(exampleEntity.id != 0)exampleEntity.id = exampleEntityBox.putAndReturnID(exampleEntity)// objectbox: entity
struct Author {
let id: Id // Do not initialize the ID to 0 for structs.
let name: String
let age: Int
}
// Let's start with an empty box:
let exampleEntityBox = store.box(for: Author.self)
let exampleEntity = Author(id: 0, name: "Nnedi Okorafor", age: 45)
// Put the immutable struct:
let newEntity = try exampleEntityBox.put(struct: exampleEntity)
assert(newEntity.id != 0)// Modify object:
let futureExampleEntity = Author(id: newEntity.id, name: newEntity:name,
age: newEntity.age + 1)
// Write out changes:
try exampleEntityBox.put(futureExampleEntity)// Bad/slow, each Put runs inside a new transaction
for i in (1...1000) {
try box.put(AnEntity(number: i))
}
// Possible, but still inefficient
try store.runInTransaction {
for i in (1...1000) {
try box.put(AnEntity(number: i))
}
}
// Much better
let allEntities: [AnEntity] = (1...1000).map(AnEntity.init(number:))
try box.put(allEntities)ObjectBox is a NoSQL Swift object database for iOS providing high-performance on mobile devices. It is an easy-to-use Core Data alternative.
canInteractWithDbStringThe swiftiest database for iOS answers the most asked questions. Is ObjectBox based on SQLite? Is ObjectBox a CoreData alternative? What about Firebase? How is ObjectBox...
/Users/vivien/RecordsDatabase/ObjectBox


The ObjectBox swift database manages the data model mostly automatically for you. Enjoy the ease of automatic schema migrations and learn here what is left to take care of.
// objectbox: entity
// objectbox: uid
class MyName { ... }error: No UID given for entity MyName. You can do the following:
[Rename] Apply the current UID using // objectbox: uid = 17664
[Change/Reset] Apply a new UID using // objectbox: uid = 18688
// objectbox: entity
// objectbox: uid = 17664
class MyName { ... }// objectbox: entity
// objectbox: uid = 17664
class MyNewName { ... }// old:
var year: String
// new:
var yearInt: Int// objectbox: uid
var year: Stringerror: No UID given for property year of entity MyName. You can do the following:
[Rename] Apply the current UID using // objectbox: uid = 15616
[Change/Reset] Apply a new UID using // objectbox: uid = 18688// objectbox: uid = 18688
var year: IntUnlike relational databases like SQLite, ObjectBox swift database does not require you to create a database schema. That does not mean ObjectBox is schema-less. Learn here how it is done.
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "1:712683617673955584",
"lastPropertyId": "2:5025387500910526208",
"name": "Author",
"properties": [
{
"flags": 1,
"id": "1:6336800942024279296",
"name": "id",
"type": 6
},
{
"id": "2:5025387500910526208",
"name": "name",
"type": 9
}
],
"relations": []
},
{
"id": "2:5608901830082711040",
"lastPropertyId": "6:6001769173142034944",
"name": "Note",
"properties": [
{
"flags": 1,
"id": "1:7180411752564202752",
"name": "id",
"type": 6
},
{
"id": "2:249105953415333376",
"name": "title",
"type": 9
},
{
"id": "3:5661281725891017216",
"name": "text",
"type": 9
},
{
"id": "4:8342334437465755392",
"name": "creationDate",
"type": 10
},
{
"id": "5:8881960381068888832",
"name": "modificationDate",
"type": 10
},
{
"flags": 520,
"id": "6:6001769173142034944",
"indexId": "1:6069708401898380544",
"name": "author",
"relationTarget": "Author",
"type": 11
}
],
"relations": []
}
],
"lastEntityId": "2:5608901830082711040",
"lastIndexId": "1:6069708401898380544",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 4,
"retiredEntityUids": [],
"retiredIndexUids": [],
"retiredPropertyUids": [],
"retiredRelationUids": [],
"version": 1
}