如何用 Alamofire 的 Session 包装已有的 URLSession 并检查前置要求
【免费下载链接】AlamofireElegant HTTP Networking in Swift项目地址: https://gitcode.com/GitHub_Trending/al/Alamofire
如果你的项目里已经存在一个自行创建的URLSession实例,而你又想在它上面使用 Alamofire 的Request体系(重试、拦截器、响应序列化等),就不必丢弃它重新创建——Alamofire 的Session提供了init(session:delegate:rootQueue:)初始化器,可以直接包装一个已有的URLSession。但这个初始化器带有一个便捷初始化器(init(configuration:...))所没有的前置要求,不满足时会在初始化时触发运行时错误。本文按 AdvancedUsage.md 中 "Creating Instances FromURLSessions" 一节的说明,给出完整的包装步骤,并逐条核对前置要求。
前提:依赖与平台要求
先确认工程满足 README.md 中的 Requirements 表:
- 平台:iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+;
- 工具链:Swift 6.0 / Xcode 16.0。
以 Swift Package Manager 为例,在Package.swift或 Xcode 的 Package 列表中声明依赖:
dependencies: [ .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.11.0")) ]通常依赖Alamofiretarget:
.product(name: "Alamofire", package: "Alamofire")包装前先核对三条前置要求
官方文档明确指出:除了便捷初始化器之外,Session也可以直接从URLSession初始化,但该初始化器有若干要求,因此文档推荐大多数场景使用便捷初始化器。只有确实需要接管一个已有的URLSession时,才走本文的路径。包装前需要核对以下三点:
- 不支持后台
URLSession。Alamofire 不支持配置为后台使用的URLSession(即URLSessionConfiguration的identifier非nil)。如果传入的是后台配置,初始化Session时会产生运行时错误。 delegate必须是 Alamofire 的SessionDelegate实例。同一个实例既要作为URLSession的delegate传入,又要传给Session初始化器。delegateQueue必须是一个自定义OperationQueue,并且满足:- 该队列是串行队列(
maxConcurrentOperationCount = 1); - 该队列必须有
underlyingQueue指向的DispatchQueue; - 这个
DispatchQueue必须作为rootQueue参数传给Session初始化器。
- 该队列是串行队列(
包装已有 URLSession 的步骤
以下代码块来自 AdvancedUsage.md 的 "Creating Instances FromURLSessions" 一节,可直接按原样使用:
let rootQueue = DispatchQueue(label: "org.alamofire.customQueue") let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 queue.underlyingQueue = rootQueue let delegate = SessionDelegate() let configuration = URLSessionConfiguration.af.default let urlSession = URLSession(configuration: configuration, delegate: delegate, delegateQueue: queue) let session = Session(session: urlSession, delegate: delegate, rootQueue: rootQueue)逐行对应上面的要求:
rootQueue:自定义的串行DispatchQueue,稍后作为Session的内部回调队列。文档中 "ASession'sDispatchQueues" 一节说明,自定义rootQueue必须是串行队列,requestQueue和serializationQueue则可以是串行或并行。queue:作为URLSession的delegateQueue传入的OperationQueue;maxConcurrentOperationCount = 1保证串行,underlyingQueue = rootQueue建立OperationQueue与DispatchQueue的绑定关系。delegate:SessionDelegate实例。它封装了所有URLSessionDelegate相关回调,同时是每个Request的SessionStateProvider。也可以用SessionDelegate(fileManager: .default)这类形式自定义其使用的FileManager。configuration:文档建议使用URLSessionConfiguration.af.default作为起点,因为它是 Alamofire 默认添加Accept-Encoding、Accept-Language和User-Agent请求头的配置,但任何URLSessionConfiguration都可以使用。注意两点:URLSessionConfiguration不是设置Authorization或Content-Type头的推荐位置(应通过Request的headersAPI、ParameterEncoder或RequestAdapter添加);且URLSessionConfiguration一旦被用于初始化URLSession,之后再修改其属性不再生效。urlSession:按上述 delegate 与队列要求创建的URLSession。session:最后把urlSession、delegate、rootQueue三者传给Session初始化器,得到可直接发请求的Session实例。
Session(session:delegate:rootQueue:)的完整参数(含startRequestsImmediately、requestSetup、requestQueue、serializationQueue、interceptor、serverTrustManager、redirectHandler、cachedResponseHandler、eventMonitors等可选项)可在 Session.swift 中查看。
如何判断前置要求是否满足
初始化器内部有两处运行时检查,对应文档列出的前置要求(见 Session.swift):
precondition(session.configuration.identifier == nil, "Alamofire does not support background URLSessionConfigurations.") precondition(session.delegateQueue.underlyingQueue === rootQueue, "Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")据此可以这样核对:
- 如果
URLSession的configuration.identifier非nil(后台配置),初始化即触发第一条precondition的运行时错误,这正是文档所说 "This will lead to a runtime error when theSessionis initialized"; - 如果传给
Session的rootQueue与URLSession的delegateQueue的underlyingQueue不是同一个DispatchQueue实例(注意是===恒等判断,不是同名队列),会触发第二条precondition; - 反过来,只要
Session初始化成功、没有触发上述运行时错误,就说明三条前置要求都已满足。此时可以像使用Session.default一样通过该实例发请求,例如文档示例中的session.request("https://httpbin.org/get")。
源码中对该初始化器的注释也重申了这一点:创建URLSession时必须使用特定的delegateQueue值,并把该delegateQueue的underlyingQueue作为rootQueue参数传入。
限制与替代路径
不需要复用已有
URLSession时,请使用便捷初始化器。文档对Creating Instances From URLSessions这一节的原话是:由于该初始化器要求较多,"using the convenience initializer is recommended"。便捷初始化器会替你创建URLSession、OperationQueue和delegateQueue,并把自定义rootQueue重新 target 成串行队列以保证安全,例如:let session = Session(configuration: URLSessionConfiguration.af.default)它同样有后台配置限制(
configuration.identifier非nil时触发同样的运行时错误)。后台传输需求不在支持范围内。无论走哪个初始化器,后台
URLSessionConfiguration都不被支持,需要后台传输时应保留自己的原生URLSession方案,而不是尝试包装。rootQueue必须串行。这是文档对Session队列的硬性说明,与便捷初始化器内部自动 target 成串行的行为不同——走init(session:)路径时这个约束由你自己在创建队列时保证。包装完成后,
Session级别的其他定制(RequestInterceptor、ServerTrustManager、RedirectHandler、CachedResponseHandler、EventMonitor等)在两条初始化路径上都可以按各自文档章节添加,与是否包装已有URLSession无关,本文不展开。
【免费下载链接】AlamofireElegant HTTP Networking in Swift项目地址: https://gitcode.com/GitHub_Trending/al/Alamofire
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考