Swiftpack.co - mediamonks/MMMPropertyWrappers as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by mediamonks.
mediamonks/MMMPropertyWrappers 0.3.1
Small collection of property wrappers.
⭐️ 1
🕓 2 years ago
iOS macOS watchOS tvOS
.package(url: "https://github.com/mediamonks/MMMPropertyWrappers.git", from: "0.3.1")

MMMPropertyWrappers

Build Test

Small collection of property wrappers.

(This is a part of MMMTemple suite of iOS libraries we use at MediaMonks.)

Installation

Podfile:

source 'https://github.com/mediamonks/MMMSpecs.git'
source 'https://github.com/CocoaPods/Specs.git'
...
pod 'MMMPropertyWrappers'

SPM:

.package(url: "https://github.com/mediamonks/MMMPropertyWrappers", .upToNextMajor(from: "0.1.0"))

Usage

Simple examples for each property wrapper.

@Once

A wrapper that allows to set a value only once after setting the initial value. This comes in useful in instances where you want to freeze the value after configuring it.

For instance on configuration object, where you want to assign a default value, but give the user the ability to alter this value in a configuration callback.

class Config {
    @Once var myValue: Bool = false
    @Once var otherValue: Bool = false

    init(_ config: (Config) -> Void) {
        config(self)
    }
}

// At call site
let config = Config {
    $0.myValue = true
}

Now config.myValue is 'frozen', if you try setting it afterwards it will throw an assertionFailure. However, config.otherValue is still open, since the user decided not to alter that value, so it's wise to call .freeze() after your configuration block.

init(_ config: (Config) -> Void) {
    config(self)

    _myValue.freeze()
    _otherValue.freeze()
}

@Lazy

A wrapper that mimicks Swift's own lazy var, with the upside of the ability to reset the generated value. This can come in handy if you want to cleanup after chaning state for instance, but want to avoid working with optionals (e.g. when values are always available to begin with).

It's also possible to update the closure that generates the value.

public final class ViewModel {
    @Lazy public private(set) var myValue = MyClass(foo: false)
    @Lazy public private(set) var myInteger = 1
    
    public func action() {
		
		print(myValue.foo) // Now myValue is instantiated, foo will be false.
		print(myInteger) // == 1
		
		myInteger = 2
		print(myInteger) // == 2
		
		_myValue.reset() // Now MyClass.deinit is hit.
		_myInteger.reset()
		
		print(myValue.someValue) // Now myValue is re-instantiated.
		print(myInteger) // == 1
		
		_myValue.update(MyClass(foo: true)) // The old MyValue now hits deinit.
		_myInteger.update(50)
		
		print(myValue.foo) // Now myValue is instantiated, foo will be true.
		print(myInteger) // == 50
	}
}

// At call site
let config = Config {
    $0.myValue = true
}

Now config.myValue is 'frozen', if you try setting it afterwards it will throw an assertionFailure. However, config.otherValue is still open, since the user decided not to alter that value, so it's wise to call .freeze() after your configuration block.

init(_ config: (Config) -> Void) {
    config(self)

    _myValue.freeze()
    _otherValue.freeze()
}

@LazyConstant

Same as @Lazy, but without the ability to modify the value.

@EventTrigger

A wrapper that will trigger a SimpleEvent or LazySimpleEvent, e.g. AnySimpleEvent when the value changes. The value should conform to Equatable, and the enclosing class to EventTriggerable.

This removes a lot of boilerplate code, going from:

protocol ViewModel {

	var foo: String { get }
	var bar: String { get }

	var didChange: SimpleEventObservable { get }
}

class DefaultViewModel: ViewModel {

	public private(set) var foo: String {
		didSet {
			_didChange.trigger(if: foo != oldValue)
		}
	}

	public private(set) var bar: String {
		didSet {
			_didChange.trigger(if: bar != oldValue)
		}
	}

	private let _didChange = SimpleEvent()
	public var didChange: SimpleEventObservable { _didChange }
}

To:

class DefaultViewModel: ViewModel, EventTriggerable {

	@EventTrigger public private(set) var foo: String
	@EventTrigger public private(set) var bar: String

	private let _didChange = SimpleEvent()
	public var didChange: SimpleEventObservable { _didChange }
}

Every time foo or bar is set, and the value != oldValue, the _didChange event will trigger.

If your property does not conform to Equatable, you could use @LenientEventTrigger.

@LenientEventTrigger

Same as @EventTrigger, but without requiring to conform to Equatable, this will trigger every time the value hits didSet.

Ready for liftoff? 🚀

We're always looking for talent. Join one of the fastest-growing rocket ships in the business. Head over to our careers page for more info!

GitHub

link
Stars: 1
Last commit: 1 year ago
Advertisement: IndiePitcher.com - Cold Email Software for Startups

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics