2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RxSwiftでUserDefaults

Last updated at Posted at 2020-09-03

RxSwiftでUserDefaultsをControlPropertyとして扱う

TextField.rx.textのように双方向に対応してます。(ObserverでありObservableでもあるみたいな。)
意外とCocoaPodsで転がってそうなコードなのになかった。

UserDefaults+Rx.swift

import Foundation
import RxSwift
import RxCocoa

public extension Reactive where Base: UserDefaults {
	
	func `default`<E: Equatable>(forKey key: String) -> ControlProperty<E?> {
		let source = Observable.deferred { [weak defaults = self.base as UserDefaults] () -> Observable<E?> in
			let center = NotificationCenter.default
			let initial = defaults?.object(forKey: key) as? E
			let changes = center.rx.notification(UserDefaults.didChangeNotification)
				.map { _ in defaults?.object(forKey: key) as? E }
			
			return Observable.just(initial)
				.concat(changes)
				.distinctUntilChanged { previous, next in
					guard let previous = previous, let next = next else { return false }
					return previous == next
			}
		}
		
		let binder = Binder(self.base) { (defaults, value: E?) in
			defaults.set(value, forKey: key)
		}
		
		return ControlProperty(values: source, valueSink: binder)
	}
	
	func url(forKey key: String) -> ControlProperty<URL?> {
		let source = Observable.deferred { [weak defaults = self.base as UserDefaults] () -> Observable<URL?> in
			let center = NotificationCenter.default
			let initial = defaults?.url(forKey: key)
			let changes = center.rx.notification(UserDefaults.didChangeNotification)
				.map { _ in defaults?.url(forKey: key) }
			
			return Observable.just(initial)
				.concat(changes)
				.distinctUntilChanged { previous, next in
					guard let previous = previous, let next = next else { return false }
					return previous == next
			}
		}
		
		let binder = Binder(self.base) { (defaults, value: URL?) in
			defaults.set(value, forKey: key)
		}
		
		return ControlProperty(values: source, valueSink: binder)
	}
}

使用例

いろいろRx系ライブラリ使って書いてるんでなんとなく雰囲気だけ感じてください。
ドキュメントピッカー開いて選ばれたやつをUserDefaultsに記憶。

let documentUrl = UserDefaults.standard.rx.url(forKey: "documentUrl")

pickDocumentButton.rx.tap
	.mapTo(UIDocumentPickerViewController(documentTypes: ["public.item"], in: .open))
	.do(onNext: presentView.accept)
	.flatMapAt(\.rx.didPickDocumentAt)
	.bind(to: documentUrl)
	.disposed(by: disposeBag)
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?