Я никогда раньше не сталкивался с ошибкой таблицы свидетелей, но это мое первое занятие по тестированию пользовательских издателей, и, если я догадываюсь, я подозреваю, что происходит нечто странное и замечательное с многопоточностью, основанное на том, как изуродовали свидетеля. имя это. Полностью в море здесь, так что указатель (или указатели!) Будет высоко ценится.
Пользовательский издатель
// MARK: Custom publisher - produces a stream of Object arrays in response to change notifcations on a given Realm collection
extension Publishers {
struct Realm<Collection: RealmCollection>: Publisher {
typealias Output = Array<Collection.Element>
typealias Failure = Never // TODO: Not true but deal with this later
let collection: Collection
init(collection: Collection) {
self.collection = collection
}
func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
let subscription = RealmSubscription(subscriber: subscriber, collection: collection)
subscriber.receive(subscription: subscription)
}
}
}
// MARK: Convenience accessor function to the custom publisher
extension Publishers {
static func realm<Collection: RealmCollection>(collection: Collection) -> Publishers.Realm<Collection> {
return Publishers.Realm(collection: collection)
}
}
// MARK: Custom subscription
private final class RealmSubscription<S: Subscriber, Collection: RealmCollection>: Subscription where S.Input == Array<Collection.Element> {
private var subscriber: S?
private let collection: Collection
private var notificationToken: NotificationToken?
init(subscriber: S, collection: Collection) {
self.subscriber = subscriber
self.collection = collection
self.notificationToken = collection.observe { (changes: RealmCollectionChange) in
switch changes {
case .initial:
// Results are now populated and can be accessed without blocking the UI
print("Initial")
let _ = subscriber.receive(Array(collection.elements)) // ERROR THROWN HERE
// case .update(_, let deletions, let insertions, let modifications):
case .update(_, _, _, _):
print("Updated")
let _ = subscriber.receive(Array(collection.elements))
case .error(let error):
fatalError("\(error)")
#warning("Impl error handling - do we want to fail or log and recover?")
}
}
}
func request(_ demand: Subscribers.Demand) {
// no impl as RealmSubscriber is effectively just a sink
}
func cancel() {
print("Cancel called on RealnSubscription")
subscriber = nil
notificationToken = nil
}
}
Класс обслуживания
protocol RealmServiceType {
func all<Element>(_ type: Element.Type, within realm: Realm) -> AnyPublisher<Array<Element>, Never> where Element: Object
@discardableResult
func addPatient(_ name: String, to realm: Realm) throws -> AnyPublisher<Patient, Never>
func deletePatient(_ patient: Patient, from realm: Realm)
}
extension RealmServiceType {
func all<Element>(_ type: Element.Type) -> AnyPublisher<Array<Element>, Never> where Element: Object {
print("Called \(#function)")
return all(type, within: try! Realm())
}
}
final class TestRealmService: RealmServiceType {
private let patients = [
Patient(name: "Tiddles"), Patient(name: "Fang"), Patient(name: "Phoebe"), Patient(name: "Snowy")
]
init() {
let realm = try! Realm()
guard realm.isEmpty else { return }
try! realm.write {
for p in patients {
realm.add(p)
}
}
}
func all<Element>(_ type: Element.Type, within realm: Realm) -> AnyPublisher<Array<Element>, Never> where Element: Object {
return Publishers.realm(collection: realm.objects(type).sorted(byKeyPath: "name")).eraseToAnyPublisher()
}
func addPatient(_ name: String, to realm: Realm) throws -> AnyPublisher<Patient, Never> {
let patient = Patient(name: name)
try! realm.write {
realm.add(patient)
}
return Just(patient).eraseToAnyPublisher()
}
func deletePatient(_ patient: Patient, from realm: Realm) {
try! realm.write {
realm.delete(patient)
}
}
}
Контрольный пример
class AthenaVSTests: XCTestCase {
private var cancellables = Set<AnyCancellable>()
private var service: RealmServiceType?
override func setUp() {
service = TestRealmService()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
service = nil
cancellables.removeAll()
}
func testRealmPublisher() {
var outcome = [""]
let expectation = self.expectation(description: #function)
let expected = ["Tiddles", "Fang", "Phoebe", "Snowy"]
let _ = service?.all(Patient.self)
.sink(receiveCompletion: { _ in
expectation.fulfill() },
receiveValue: { value in
outcome += value.map { $0.name }
})
.store(in: &cancellables)
waitForExpectations(timeout: 2, handler: nil)
XCTAssert(outcome == expected, "Expected \(expected) Objects but got \(outcome)")
}
}
Сообщение об ошибке
не удалось разобрать свидетеля для связанного типа «Итератор» в соответствие 'RealmSwift.Results: Sequence' из искаженного имени '10RealmSwift11RLMIteratorVyxG' 2020-01-13 22: 46: 07.159964 + 0000 AthenaVS [3423: 171342] не удалось разобрать свидетельство для связанного типа «Итератор» в соответствии «RealmSwift.Results: 'из искаженного имени' 10RealmSwift11RLMIteratorVyxG '
Ошибка при попытке выполнить код в наблюдателе уведомлений Realm в RealmSubscription (я отметил это в коде выше), а именно:
let _ = subscriber.receive(Array(collection.elements))
Идеи