我想知道是否有一种方法可以通过新的Apple框架实现重新连接机制结合并使用URLSession发布器
waitsForConnectivity
一起玩没有运气(甚至没有在自定义会话中调用委托)URLSession.background
,但在发布期间崩溃了。 我也不了解我们如何以这种方式跟踪进度
有没有人试图做过这样的事?
upd:
在Xcode 11 Beta中似乎waitsForConnectivity
is not working
upd2:
Xcode 11 GM-waitsForConnectivity
正常运行,但在设备上仅。使用默认会话,设置标志并实现会话委托。无论您是否使用带有回调的init任务,都将调用方法task is waiting for connectivity
。
public class DriverService: NSObject, ObservableObject {
public var decoder = JSONDecoder()
public private(set) var isOnline = CurrentValueSubject<Bool, Never>(true)
private var subs = Set<AnyCancellable>()
private var base: URLComponents
private lazy var session: URLSession = {
let config = URLSessionConfiguration.default
config.waitsForConnectivity = true
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
public init(host: String, port: Int) {
base = URLComponents()
base.scheme = "http"
base.host = host
base.port = port
super.init()
// Simulate online/offline state
//
// let pub = Timer.publish(every: 3.0, on: .current, in: .default)
// pub.sink { _ in
// let rnd = Int.random(in: 0...1)
// self.isOnline.send(rnd == 1)
// }.store(in: &subs)
// pub.connect()
}
public func publisher<T>(for driverRequest: Request<T>) -> AnyPublisher<T, Error> {
var components = base
components.path = driverRequest.path
var request = URLRequest(url: components.url!)
request.httpMethod = driverRequest.method
return Future<(data: Data, response: URLResponse), Error> { (complete) in
let task = self.session.dataTask(with: request) { (data, response, error) in
if let err = error {
complete(.failure(err))
} else {
complete(.success((data!, response!)))
}
self.isOnline.send(true)
}
task.resume()
}
.map({ $0.data })
.decode(type: T.self, decoder: decoder)
.eraseToAnyPublisher()
}
}
extension DriverService: URLSessionTaskDelegate {
public func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {
self.isOnline.send(false)
}
}
答案 0 :(得分:0)
您是否尝试过retry(_:)
?它在Publisher
上可用,并在失败时重新运行请求。
如果您不希望请求针对所有失败立即重新运行,则可以使用catch(_:)
并确定哪些失败需要重新运行。
这里有一些代码可以实现进度。
enum Either<Left, Right> {
case left(Left)
case right(Right)
var left: Left? {
switch self {
case let .left(value):
return value
case .right:
return nil
}
}
var right: Right? {
switch self {
case let .right(value):
return value
case .left:
return nil
}
}
}
extension URLSession {
func dataTaskPublisherWithProgress(for url: URL) -> AnyPublisher<Either<Progress, (data: Data, response: URLResponse)>, URLError> {
typealias TaskEither = Either<Progress, (data: Data, response: URLResponse)>
let completion = PassthroughSubject<(data: Data, response: URLResponse), URLError>()
let task = dataTask(with: url) { data, response, error in
if let data = data, let response = response {
completion.send((data, response))
completion.send(completion: .finished)
} else if let error = error as? URLError {
completion.send(completion: .failure(error))
} else {
fatalError("This should be unreachable, something is clearly wrong.")
}
}
task.resume()
return task.publisher(for: \.progress.completedUnitCount)
.compactMap { [weak task] _ in task?.progress }
.setFailureType(to: URLError.self)
.map(TaskEither.left)
.merge(with: completion.map(TaskEither.right))
.eraseToAnyPublisher()
}
}
答案 1 :(得分:-1)
我多次阅读了您的问题标题。如果您的意思是重新连接URLSession的发布者。由于Too few arguments to function Illuminate\Support\Manager::createDriver(), 0 passed in /mnt/web409/e0/11/59802411/htdocs/test/crm/vendor/laravel/framework/src/Illuminate/Support/Manager.php on line 96 and exactly 1 expected
有两个结果。成功输出或失败(也称为URLSession.DataTaskPublisher
)。产生输出后,无法使其重新连接。
您可以声明一个主题。例如
URLError
并在网络连接处于活动状态时添加触发器,然后请求资源并将新的let output = CurrentValueSubject<Result<T?, Error>, Never>(.success(nil))
发送到输出。在其他位置订阅输出。这样,当网络重新联机时,您可以获取 new 值。