/CombineRealm

Combine extension to Realm

Primary LanguageSwiftMIT LicenseMIT

License Swift Package Manager Carthage compatible

Build Status codecov

CombineRealm

Combine is a lightweight framework that is written is pure Swift. It allows to seamlessly use Apple Combine Framework with Realm.

Installation

CombineRealm is avaialble via Carthage or Swift Package Manager.

Requirements

  • iOS 13.0+
  • Swift 5+
  • Realm 3.21.0+
  • Carthage 0.18+ (if you use)

Carthage

To install CombineRealm with Carthage, add the following line to your Cartfile.

github "yaroslav-zhurakovskiy/CombineRealm"

Swift Package Manager

You can use The Swift Package Manager to install CombineRealm by adding the proper description to your Package.swift file:

// swift-tools-version:5.1
import PackageDescription

let package = Package(
	name: "YOUR_PROJECT_NAME",
	dependencies: [
		.package(url: "https://github.com/yaroslav-zhurakovskiy/CombineRealm.git", from: "1.2.1"),
	]
)

Usage

Observing changes

Some "Message" type that will be used in the examples

class Message: Object {
    @objc dynamic var id: String = UUID().uuidString
    @objc dynamic var body: String = ""
    
    convenience init(_ text: String) {
        self.init()

        body = text
    }
}

Observe objects

let realm = try Realm()
let infoLabel = UILabel()
var cancelSet = Set<AnyCancellable>()

realm.objectsPublisher(Message.self)
	.map { list in "You have \(list.count) messages!" }
	.catch { error in Just("Realm error: \(error.localizedDescription)") }
	.assign(to: \.text, on: infoLabel)
	.store(in: &cancelSet)

Observe collection changes

let realm = try Realm()
let infoLabel = UILabel()
var cancelSet = Set<AnyCancellable>()

realm.objects(Message.self).observeChangePublisher()
	.map { changes in
		switch changes {
		case .initial(let messages):
			return "Initial \(messages.count)"
		case let .update(messages, deletions, insertions, modifications):
			var text =  "Update \(messages.count)."
			text += "\nDeletions: \(deletions)"
			text += "\nInsertions: \(insertions)"
			text += "\nModifications: \(modifications)"
			return text
		case .error(let error):
			return "Realm error: \(error.localizedDescription)"
		}
	}
	.assign(to: \.text, on: infoLabel)
	.store(in: &cancelSet)
}

Observe changes in an object

class UserSettings: Object {
	@objc dynamic var email: String = ""
	@objc dynamic var company: String = ""
}

let userSettings = UserSettings()
let infoLabel = UILabel()
var cancelSet = Set<AnyCancellable>()

userSettings.observePublisher()
	.map { change in
		switch change {
		case .change(let properties):
			let settings = properties.map { $0.name }.joined(separator: "")
			return "User changed settings: \(settings)"
		case .deleted:
			return "User deleted the settings."
		}
	}
	.catch { error in Just("Realm error: \(error.localizedDescription)") }
	.assign(to: \.text, on: infoLabel)
	.store(in: &cancelSet)

Writing changes

let realm = try Realm()
let currentMessage = Message("Some message to edit...")
try realm.write {
	realm.add(currentMessage)
}
let editMessageField =  UITextField()
var cancellableSet = Set<AnyCancellable>()

editMessageField.publisher(for: \.text)
	.map { $0 ?? "" }
	.write(to: realm) { _, newMessageText in
		currentMessage.body = newMessageText
	}
	.store(in: &cancellableSet)

Adding objects

let realm = try Realm()
var cancelSet = Set<AnyCancellable>()
let messageField =  UITextField()
let sendButton = UIButton()

sendButton.publisher(for: .touchUpInside) 
	.compactMap { messageField.text }
	.filter { text in !text.isEmpty }
	.map { text in Message(text) }
	.add(to: realm)
	.store(in: &cancelSet)

Just(Message("I am great!"))
	.add(to: realm)
	.store(in: &cancelSet)

Deleting objects

let realm = try Realm()
var cancelSet = Set<AnyCancellable>()

Publishers.Sequence(sequence: ["message-id#1", "message-id#2"])
	.compactMap { messageID in
		return realm.object(ofType: Message.self, forPrimaryKey: messageID)
	}
	.delete(from: realm)
	.store(in: &cancelSet)

Note

Instead of sugar syntax you can always use the coresponding types:

// Publishers
ObserveChangePublisher
ObserveElementsPublisher
ObserveObjectPublisher

// Subscribers
Realm.Add
Realm.Write
Realm.TryWrite
Realm.Delete