Не удалось устранить ошибку свидетеля при использовании области в настраиваемом издателе - PullRequest
0 голосов
/ 14 января 2020

Я никогда раньше не сталкивался с ошибкой таблицы свидетелей, но это мое первое занятие по тестированию пользовательских издателей, и, если я догадываюсь, я подозреваю, что происходит нечто странное и замечательное с многопоточностью, основанное на том, как изуродовали свидетеля. имя это. Полностью в море здесь, так что указатель (или указатели!) Будет высоко ценится.

Пользовательский издатель

// 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))

Идеи

1 Ответ

0 голосов
/ 16 января 2020

Это была красная сельдь, но, вообще говоря, связанная с Combine, а не с какой-то проблемой сборки Swift, попробуйте переключиться на Carthage вместо использования SPM, чтобы посмотреть, исчезнет ли проблема.

Для других эта ссылка может быть релевантной

...