← Назад к вопросам

Какие знаешь базовые Observable в Combine?

2.2 Middle🔥 111 комментариев
#Архитектура и паттерны#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Основные Observable-типы в Combine

В Combine, фреймворке реактивного программирования от Apple, существует несколько базовых типов, которые реализуют протокол Publisher и служат основой для создания и работы с потоками данных. Вот ключевые из них:

1. Just

Just — это publisher, который испускает единственное значение, а затем завершается. Он не может выдать ошибку (ошибка имеет тип Never). Идеально подходит для передачи фиксированных значений.

import Combine

let justPublisher = Just("Hello, Combine!")
justPublisher
    .sink { value in
        print("Received value: \(value)")
    }
// Выведет: Received value: Hello, Combine!

2. Future

Future — используется для асинхронных операций, которые возвращают одно значение или ошибку. Он создаётся с замыканием, которое принимает Promise — это замыкание, вызываемое с результатом (Result<Output, Failure>).

func fetchData() -> Future<String, Error> {
    return Future { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            promise(.success("Data loaded"))
            // promise(.failure(NetworkError.timeout)) в случае ошибки
        }
    }
}

fetchData()
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("Error: \(error)")
        }
    }, receiveValue: { value in
        print(value)
    })

3. Empty

Empty — publisher, который не испускает никаких значений и может быть настроен на немедленное завершение. Полезен в цепочках операторов, где нужно игнорировать значения или передать завершение.

let emptyPublisher = Empty<String, Never>()
emptyPublisher
    .sink(receiveCompletion: { _ in
        print("Completed")
    }, receiveValue: { value in
        print(value) // Никогда не выполнится
    })
// Выведет: Completed

4. Fail

Fail — publisher, который сразу завершается с указанной ошибкой, не испуская значений. Используется для моделирования ошибочных сценариев.

enum CustomError: Error {
    case somethingWentWrong
}

let failPublisher = Fail<String, CustomError>(error: .somethingWentWrong)
failPublisher
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("Failed with error: \(error)")
        }
    }, receiveValue: { _ in })
// Выведет: Failed with error: somethingWentWrong

5. Deferred

Deferred — создаёт publisher только тогда, когда на него подписываются. Это полезно для того, чтобы избежать создания ресурсов до фактической подписки.

let deferredPublisher = Deferred {
    return Just("Создано при подписке")
}
deferredPublisher
    .sink { print($0) }
// Выведет: Создано при подписке

6. Record

Record — publisher, который записывает последовательность значений и завершение для последующего воспроизведения. Похож на предзаписанную ленту событий.

let record = Record<String, Never>(output: ["A", "B", "C"], completion: .finished)
record
    .sink(receiveCompletion: { _ in print("Done") },
          receiveValue: { print($0) })
// Выведет:
// A
// B
// C
// Done

7. Subject (PassthroughSubject и CurrentValueSubject)

Хотя Subject — это скорее механизм для инжекции значений в поток, они также являются publisher'ами:

  • PassthroughSubject — передаёт значения подписчикам, но не хранит текущее значение.
  • CurrentValueSubject — хранит текущее значение и отправляет его новым подписчикам.
// PassthroughSubject
let passthrough = PassthroughSubject<String, Never>()
passthrough.send("Hello")
passthrough.sink { print($0) }
passthrough.send("World") // Выведет: World

// CurrentValueSubject
let current = CurrentValueSubject<String, Never>("Initial")
current.sink { print($0) } // Выведет: Initial
current.send("Updated") // Выведет: Updated

Ключевые особенности:

  • Just, Future, Empty, Fail — это стоимостные типы, которые описывают конкретные сценарии потока данных.
  • Deferred обеспечивает ленивую инициализацию, что помогает оптимизировать ресурсы.
  • Record полезен для тестирования, так как позволяет воспроизводить предопределённые последовательности.
  • Subject'ы часто выступают как мосты между императивным и реактивным кодом, позволяя "вручную" отправлять значения.

Эти базовые publisher'ы служат строительными блоками для более сложных реактивных цепочек, комбинируясь с операторами (map, filter, flatMap и т.д.) и подписчиками (sink, assign). Понимание их поведения критично для эффективного использования Combine в iOS-разработке, особенно при работе с асинхронными операциями, обработке ошибок и управлении жизненным циклом данных.

Какие знаешь базовые Observable в Combine? | PrepBro