What is RxSwift?
masterObservable<Element> interface. It is designed to enable easy composition of asynchronous operations and event/data streams by unifying KVO observing, async operations, and streams under the abstraction of a sequence.repository·master·Indexed 23 days ago
https://github.com/ios-swift-developers/swiftA comprehensive learning repository for Swift developers covering basic syntax and advanced applications. The documentation includes detailed guides on using Alamofire for HTTP networking, featuring request/response methods, parameter encoding, SessionManager configuration, and the implementation of the Router pattern via URLRequestConvertible. It also covers advanced networking topics such as RequestAdapter and RequestRetrier for OAuth2 refresh flows, custom response serialization, and the use of AlamofireImage and AlamofireNetworkActivityIndicator.
Observable<Element> interface. It is designed to enable easy composition of asynchronous operations and event/data streams by unifying KVO observing, async operations, and streams under the abstraction of a sequence.Alamofire is an HTTP networking library for Swift that provides:
URLCredentialKingfisher is a lightweight, pure-Swift library for downloading and caching images from the web. Key features include:
URLSession-based networking.UIImageView, NSImage, and UIButton.Use ServerTrustPolicyManager to map different ServerTrustPolicy configurations to specific hosts. This allows you to apply strict pinning to sensitive domains while using default evaluation or disabling evaluation for others.
Important: You must keep a strong reference to the SessionManager instance containing the ServerTrustPolicyManager, otherwise requests will be cancelled when the manager is deallocated.
To implement custom matching logic (like wildcard domains), subclass ServerTrustPolicyManager and override serverTrustPolicy(forHost:).
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"test.example.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
),
"insecure.expired-apis.com": .disableEvaluation
]
let sessionManager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
class CustomServerTrustPolicyManager: ServerTrustPolicyManager {
override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
var policy: ServerTrustPolicy?
// Implement custom domain matching behavior...
return policy
}
}The SessionDelegate handles URLSession delegate callbacks. You can customize this behavior in two ways:
subdelegates are managed by the default implementation.Commonly used override closures include:
sessionDidReceiveChallenge: For authentication challenges.sessionDidFinishEventsForBackgroundURLSession: For background session completion.taskWillPerformHTTPRedirection: For handling HTTP redirects.dataTaskWillCacheResponse: For managing response caching.// Example: Using an override closure to prevent redirects to apple.com
let sessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default)
let delegate: Alamofire.SessionDelegate = sessionManager.delegate
delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
var finalRequest = request
if let originalRequest = task.originalRequest,
let urlString = originalRequest.url?.urlString,
urlString.contains("apple.com") {
finalRequest = originalRequest
}
return finalRequest
}
// Example: Subclassing SessionDelegate for logging
class LoggingSessionDelegate: SessionDelegate {
override func urlSession(
_ session: URLSession,
task: URLSessionTask,
willPerformHTTPRedirection response: HTTPURLResponse,
newRequest request: URLRequest,
completionHandler: @escaping (URLRequest?) -> Void)
{
print("URLSession will perform HTTP redirection to request: \(request)")
super.urlSession(
session,
task,
willPerformHTTPRedirection: response,
newRequest: request,
completionHandler: completionHandler
)
}
}RxSwift is a generic abstraction of computation expressed through the Observable<Element> interface. It unifies KVO observing, asynchronous operations, and data streams under the single abstraction of a sequence.
Key concepts include:
Single, Completable, Maybe, Driver, ControlProperty, and Variable that provide specific semantic guarantees.throttle, flatMapLatest, distinctUntilChanged).For complex applications, use the URLRequestConvertible protocol to implement the Router pattern. This allows you to centralize endpoint definitions, manage HTTP methods (GET, POST, etc.), handle parameter encoding, and manage authentication in a single, type-safe enum.
This approach abstracts away server-side inconsistencies and provides a clean API for the rest of your application.
// Example: A Router for search functionality
enum Router: URLRequestConvertible {
case search(query: String, page: Int)
static let baseURLString = "https://example.com"
static let perPage = 50
func asURLRequest() throws -> URLRequest {
let result: (path: String, parameters: Parameters) = {
switch self {
case let .search(query, page) where page > 0:
return ("/search", ["q": query, "offset": Router.perPage * page])
case let .search(query, _):
return ("/search", ["q": query])
}
}()
let url = try Router.baseURLString.asURL()
.appendingPathComponent(result.path)
let urlRequest = URLRequest(url: url)
return try URLEncoding.default.encode(urlRequest, with: result.parameters)
}
}
// Usage
Alamofire.request(Router.search(query: "foo bar", page: 1))
// Resulting URL: https://example.com/search?q=foo%20bar&offset=50The Alamofire Software Foundation provides additional libraries to extend functionality:
UIImage/UIImageView extensions, custom filters, an in-memory cache, and a priority-based downloading system.To achieve automatic, type-safe serialization of JSON responses into Swift objects, implement the ResponseObjectSerializable protocol. This allows you to add a .responseObject() method to DataRequest.
ResponseObjectSerializable with an initializer: init?(response: HTTPURLResponse, representation: Any).DataRequest to include a responseObject<T: ResponseObjectSerializable> method that uses a DataResponseSerializer to parse JSON and then initialize the object.protocol ResponseObjectSerializable {
init?(response: HTTPURLResponse, representation: Any)
}
struct User: ResponseObjectSerializable {
let username: String
let name: String
init?(response: HTTPURLResponse, representation: Any) {
guard
let username = response.url?.lastPathComponent,
let representation = representation as? [String: Any],
let name = representation["name"] as? String
else { return nil }
self.username = username
self.name = name
}
}
Alamofire.request("https://example.com/users/mattt").responseObject { (response: DataResponse<User>) in
if let user = response.result.value {
print("User: { username: \(user.username), name: \(user.name) }")
}
}Alamofire provides the RequestAdapter and RequestRetrier protocols to handle complex authentication flows (like OAuth2) in a thread-safe manner.
RequestAdapter: Allows you to inspect and modify a URLRequest before it is sent. A common use case is appending an Authorization header (e.g., a Bearer token) to requests.RequestRetrier: Allows you to intercept a request that encountered an error and decide whether it should be retried. This is ideal for implementing credential refresh logic (e.g., catching a 401 Unauthorized error, refreshing the token, and retrying the original request).You can assign an object conforming to these protocols to a SessionManager's adapter and retrier properties.
// Example: Using an adapter to add an Authorization header
class AccessTokenAdapter: RequestAdapter {
private let accessToken: String
init(accessToken: String) { self.accessToken = accessToken }
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
var urlRequest = urlRequest
if let urlString = urlRequest.url?.absoluteString, urlString.hasPrefix("https://httpbin.org") {
urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
}
return urlRequest
}
}
let sessionManager = SessionManager()
sessionManager.adapter = AccessTokenAdapter(accessToken: "1234")
sessionManager.request("https://httpbin.org/get")To manage complex network stacks, use the Router pattern by adopting these protocols:
Use this to map domain models to URLs. Types like String, URL, and URLComponents conform by default. Custom types can implement asURL() to provide type-safe endpoint construction.
This is the recommended way to specify custom HTTP bodies and headers for individual requests. It allows you to encapsulate endpoint logic, parameter encoding, and authentication into a single type (often an enum).
// Example: URLConvertible for type-safe user URLs
extension User: URLConvertible {
static let baseURLString = "https://example.com"
func asURL() throws -> URL {
let urlString = User.baseURLString + "/users/\(username)/"
return try urlString.asURL()
}
}
// Example: URLRequestConvertible Router for API Parameter Abstraction
enum Router: URLRequestConvertible {
case search(query: String, page: Int)
static let baseURLString = "https://example.com"
static let perPage = 50
func asURLRequest() throws -> URLRequest {
let result: (path: String, parameters: Parameters) = {
switch self {
case let .search(query, page) where page > 0:
return ("/search", ["q": query, "offset": Router.perPage * page])
case let .search(query, _):
return ("/search", ["q": query])
}
}()
let url = try Router.baseURLString.asURL()
let urlRequest = URLRequest(url: url.appendingPathComponent(result.path))
return try URLEncoding.default.encode(urlRequest, with: result.parameters)
}
}
// Usage
Alamofire.request(Router.search(query: "foo bar", page: 1)) // ?q=foo%20bar&offset=50GPUImage uses OpenGL ES 2.0 shaders to perform high-speed image and video manipulation. It abstracts the complexity of the OpenGL ES API through a simplified Objective-C interface.
The processing model follows a chain of objects:
GPUImageOutput subclasses): These upload frames as textures. Common sources include:GPUImageVideoCamera: Live video from the iOS camera.GPUImageStillCamera: For taking photos with the camera.GPUImagePicture: For still images.GPUImageMovie: For movies.GPUImageInput protocol): These receive textures from the previous link in the chain, apply effects, and pass them down.GPUImageView, saving to a UIImage, or writing to a movie file on disk).Processing can be branched by adding multiple targets to a single output or filter.