CaptureContext/swift-marker-protocols
Marker protocols for common classes in Apple SDKs
Table of contents
- Methods on generic Self - Properties on generic Self - Optionals
Motivation
Marker protocols is an approach of partially erasing type constraints for writing generic extensions for types in Swift.
Such protocols can be required by different packages and declaring them in-place may cause name collisions.
This lightweight package declares a set of core marker protocols to potentially address such collisions.
Examples
Marker protocols are useful for building type-aware generic extensions.
Methods on generic Self
Without MarkerProtocols
extension AVCaptureDevice {
func withExclusiveLock(
// ❌ `Self` can't be used on non-final class AVCaptureDevice
perform configuration: (AVCaptureDevice) async -> Void
) async throws {
try self.lockForConfiguration()
await configuration(self)
self.unlockForConfiguration()
}
}
let instance: CustomAVCaptureDevice = .init()
instance.withExlusiveLock { device in
// ❌ Type of device is erased to AVCaptureDevice
// not just base AVCaptureDevice
}With MarkerProtocols
import AVFoundationMarkerProtocols
extension _AVCaptureDeviceProtocol {
func withExclusiveLock(
// ✅ `Self` can be used on a marker protocol
perform configuration: (Self) async -> Void
) async throws {
try self.lockForConfiguration()
await configuration(self)
self.unlockForConfiguration()
}
}
let instance: CustomAVCaptureDevice = .init()
instance.withExlusiveLock { device in
// ✅ Type of device is kept - CustomAVCaptureDevice
}Properties on generic Self
Lets say you want to build some layout proxy for Cocoa views
- Target API
``swift view.layout.chain.of.calls() ``
- Chainable proxy type
```swift public struct LayoutProxy<Target: UIView> { public let target: Target
internal init(_ target: Target) { self.target = target } } ```
Without MarkerProtocols
extension UIView {
// ❌ `Self` can't be used on non-final class UIView
// Using this property on any type will always
// erase a type of the view
var layout: LayoutProxy<UIView> { .init(self) }
}With MarkerProtocols
extension _UIViewProtocol {
// ✅ `Self` can be used here and the type
// of the view is kept at the call site
var layout: LayoutProxy<Self> { .init(self) }
}Optionals
struct GenericContainer<Content> {
var content: Content
}Without MarkerProtocols
extension GenericContainer {
// This declaration is completely fine, except
// of being a bit too verbose
func unwrapped<Value>(with value: Value) -> GenericContainer<Value>
where Content == Value {
.init(content: content ?? value)
}
// ❌ Won't compile since properties can't be
// generic and we can't declare `Value` type here
var unsafelyUnwrapped: GenericContainer<Value> { /*...*/ }
}With MarkerProtocols
extension GenericContainer where Content: _OptionalProtocol {
func unwrapped(with value: Value) -> GenericContainer<Value> {
.init(with: content._optional ?? value)
}
var unsafelyUnwrapped: GenericContainer<Content.Wrapped> {
get { .init(content: content._optional!) }
set { self.content = newValue.content }
}
}Products
SwiftMarkerProtocols
_OptionalProtocol<Wrapped>_AnyKeyPathProtocol- alternative toSwift._AppendKeyPathprotocol
QuartzCoreMarkerProtocols
_CALayerProtocol- Exports
FoundationMarkerProtocols
AVFoundationMarkerProtocols
_AVCaptureDeviceProtocol- Exports
FoundationMarkerProtocols
FoundationMarkerProtocols
_NotificationCenterProtocol- Exports
SwiftMarkerProtocols
CocoaMarkerProtocols
_UIViewProtocol/_NSViewProtocol_UIViewControllerProtocol/_NSViewControllerProtocol- Exports
FoundationMarkerProtocols
[!TIP]
UIKitis basically a CocoaTouch frameworkAppKitis basically Cocoa framework withoutCoreDataBoth frameworks could have shared
Cocoaprefix for their types, so capturecontext/cocoa-aliases package providesCocoa-prefixed aliases forUI/NSprefixed Cocoa types, it also exports aliased_CocoaViewProtocoland_CocoaViewControllerProtocolmarker protocols.
MarkerProtocols
This is an umbrella product that exports all available marker protocols.
Installation
Primary targets for this package are other packages
.package(
url: "https://github.com/capturecontext/swift-marker-protocols.git",
.upToNextMajor(from: "1.1.0")
)Do not forget about target dependencies:
.product(
name: "MarkerProtocols",
package: "swift-marker-protocols"
)License
This library is released under the MIT license. See LICENSE for details.
Package Metadata
Repository: CaptureContext/swift-marker-protocols
Stars: 0
Forks: 0
Open issues: 0
Default branch: main
Primary language: swift
License: MIT
Topics: avfoundation, cocoa, foundation, metaprogramming, quartzcore, swift, uikit
README: README.md