A description of this package. This provides some features that were only available at least iOS 15 and macOS 12.
iOS 15, macOS 12 등에서만 사용이 가능한 API를 iOS 13, iOS 10.15 등에서 사용할 수 있도록 하는 것으로 목표로 개발되었습니다.
async await URLSession download, upload
async await NSManagedContext peform
Combine <-> AsyncSequence interchanging
SwiftUI.AsyncImage SwiftUI.Binding Collction conformance SwiftUI.List Pull to Refresh
(Try)MapTask
Transform upstream value using async (throwing) closure in Serial manner.
Only one transformer runs at a time.
Wil be migrated to MultiMapTask
.
import Combine
import Tetra
let cancellable = (0..<20).publisher
.tryMapTask { _ in
// Underlying Task is cancelled if subscription is cancelled before task completes.
try await URLSession.shared.data(from: URL(string: "https://google.com")!)
}.map(\.0).sink { completion in
} receiveValue: { data in
}
MultiMapTask
!ExperimantalTransform upstream value using async closure in Concurrent manner.
Transformer runs up to maxTasks
in concurrent manner managed by TaskGroup.
maxTasks = 1
has same behavior with (Try)MapTask.
import Combine
@_spi(Experimental) import Tetra
let cancellable = (0..<20).publisher
.setFailureType(to: URLError.self)
.multiMapTask(maxTasks: .unlimited) { _ in
// Underlying Task is cancelled if subscription is cancelled before task completes.
do {
let (data, response) = try await URLSession.shared.data(from: URL(string: "https://google.com")!)
return .success(data) as Result<Data,URLError>
} catch {
return .failure(error as! URLError) as Result<Data,URLError>
}
}.sink { completion in
} receiveValue: { data in
}
AsyncSequencePublisher
Transform AsyncSequence to Publisherimport Combine
import Tetra
let cancellable = AsyncStream<Int> { continuation in
continuation.yield(0)
continuation.yield(1)
continuation.finish()
// Underlying AsyncIterator and Task receive task cancellation if subscription is cancelled.
}.tetra.publisher
.catch{ _ in Empty().setFailureType(to: Never.self) }
.sink { number in
}
[NotificationSequence]
AsyncSequence compatible with `NotificationCenter.Notifications` Available even in iOS 13import Combine
import Tetra
import UIKit
// use NotificationCenter.Notifications if available otherwise use NotficationSequence under the hood
for await notification in NotificationCenter.default.tetra.notifications(named: UIApplication.didFinishLaunchingNotification) {
}
CompatAsync(Throwing)Publisher
AsyncSequence compatible with `Async(Throwing)Publisher` Available even in iOS 13import Combine
import Tetra
let publisher = URLSession.shared.dataTaskPublisher(for: URL(string: "https://google.com")!)
// use AsyncThrowingPublisher if available otherwise use CompatAsyncThrowingPublisher under the hood.
for try await (data, response) in publisher.tetra.values {
}
RefreshableScrollView
Compatible pull to refresh feature in all version for iOSimport SwiftUI
import Tetra
struct ContentView: View {
var body: some View {
RefreshableScrollView {
}
.refreshControl {
await fetchData()
}
}
}
MapTask
and TryMapTask
, MultiMapTask
could lose the value when using with PublishSubject
or CurrentValueSubject
.
-
This is because, Swift does not allow running task inline(run task until reaching suspending point). So
MapTask
operators need additional time to for warmup. -
To fix this issue, use
MapTask
family inside theFlatMap
or attachbuffer
before them.
-
Add more Tests
-
Swift 6 Concurrency model
-
FullTypedThrow for powerful generic failure
-
more fine grained way to introduce extension methods (maybe something like
.af
in Alamofire?) -
remove all
AsyncTypedSequence
andWrappedAsyncSequence
dummy protocol whenFullTypedThrow
is implemented.