├── .swift-version ├── docs ├── img │ ├── gh.png │ ├── carat.png │ └── dash.png ├── docsets │ ├── ETBinding.tgz │ ├── ETLiveData.tgz │ ├── ETBinding.docset │ │ └── Contents │ │ │ ├── Resources │ │ │ ├── docSet.dsidx │ │ │ └── Documents │ │ │ │ ├── img │ │ │ │ ├── gh.png │ │ │ │ ├── dash.png │ │ │ │ └── carat.png │ │ │ │ ├── badge.svg │ │ │ │ ├── js │ │ │ │ └── jazzy.js │ │ │ │ ├── undocumented.json │ │ │ │ ├── Structs.html │ │ │ │ ├── css │ │ │ │ └── highlight.css │ │ │ │ ├── Typealiases.html │ │ │ │ ├── Functions.html │ │ │ │ ├── Enums.html │ │ │ │ ├── Protocols.html │ │ │ │ └── Structs │ │ │ │ └── FatalErrorUtil.html │ │ │ └── Info.plist │ └── ETLiveData.docset │ │ └── Contents │ │ ├── Resources │ │ ├── Documents │ │ │ ├── undocumented.json │ │ │ ├── img │ │ │ │ ├── gh.png │ │ │ │ ├── carat.png │ │ │ │ └── dash.png │ │ │ ├── badge.svg │ │ │ ├── js │ │ │ │ └── jazzy.js │ │ │ ├── search.json │ │ │ ├── Structs.html │ │ │ ├── css │ │ │ │ └── highlight.css │ │ │ ├── Enums.html │ │ │ ├── Enums │ │ │ │ ├── LifecycleState.html │ │ │ │ └── StateValue.html │ │ │ └── Functions.html │ │ └── docSet.dsidx │ │ └── Info.plist ├── badge.svg ├── js │ └── jazzy.js ├── undocumented.json ├── Structs.html ├── css │ └── highlight.css ├── Typealiases.html ├── Functions.html ├── Enums.html ├── Protocols.html └── Structs │ └── FatalErrorUtil.html ├── Configs ├── iOS │ └── ETObserver.framework │ │ ├── ETObserver │ │ ├── Info.plist │ │ ├── Modules │ │ ├── module.modulemap │ │ └── ETObserver.swiftmodule │ │ │ ├── arm.swiftdoc │ │ │ ├── arm.swiftmodule │ │ │ ├── arm64.swiftdoc │ │ │ ├── i386.swiftdoc │ │ │ ├── x86_64.swiftdoc │ │ │ ├── arm64.swiftmodule │ │ │ ├── i386.swiftmodule │ │ │ └── x86_64.swiftmodule │ │ └── Headers │ │ └── ETObserver-Swift.h ├── ETBindingTests.plist └── ETBinding.plist ├── Tests └── LinuxMain.swift ├── ETBinding.xcodeproj ├── project.xcworkspace │ ├── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist │ └── contents.xcworkspacedata └── xcshareddata │ ├── xcbaselines │ └── 52D6D9851BEFF229002C0205.xcbaseline │ │ ├── 38D69606-11F5-4043-B894-0F850F690971.plist │ │ └── Info.plist │ └── xcschemes │ ├── ETBinding-watchOS.xcscheme │ ├── ETBinding-iOS.xcscheme │ ├── ETBinding-tvOS.xcscheme │ └── ETBinding-macOS.xcscheme ├── Sources ├── ETBinding │ ├── Constants.swift │ ├── LiveData │ │ ├── LiveStateData.swift │ │ ├── StateValue.swift │ │ ├── LiveOptionalStateData.swift │ │ └── LiveOptionalData.swift │ ├── Observable │ │ ├── LifecycleState.swift │ │ ├── Observer.swift │ │ ├── LifecycleBoundObserver.swift │ │ └── Observable.swift │ ├── Helpers │ │ └── DeallocTracker.swift │ └── FutureEvent │ │ └── FutureEvent.swift └── ETBindingTests │ ├── Helpers │ └── Curry.swift │ ├── PerformanceTests.swift │ └── LiveStateDataTests.swift ├── .travis.yml ├── ETBinding.podspec ├── Package.swift ├── LICENSE ├── .gitignore └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/ETBinding.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETBinding.tgz -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETLiveData.tgz -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/ETObserver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/ETObserver -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Info.plist -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import ETLiveDataTests 3 | 4 | XCTMain([ 5 | testCase(ETLiveDataTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module ETObserver { 2 | header "ETObserver-Swift.h" 3 | requires objc 4 | } 5 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETBinding.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/jancislinsky/Repos/iOS/ETLiveData" 6 | } -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETLiveData.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETBinding.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/docs/docsets/ETLiveData.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm.swiftdoc -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm.swiftmodule -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm64.swiftdoc -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/i386.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/i386.swiftdoc -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/arm64.swiftmodule -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/i386.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/i386.swiftmodule -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtneteraMobile/ETBinding/HEAD/Configs/iOS/ETObserver.framework/Modules/ETObserver.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /ETBinding.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/ETBinding/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 15. 12. 2017. 6 | // Copyright © 2017 ETBinding. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | internal struct Constants { 12 | internal static let startVersion = -1 13 | } 14 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/ETBindingTests/Helpers/Curry.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Curry.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 20. 12. 2017. 6 | // Copyright © 2017 ETBinding. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | func curry(_ f: @escaping (A, B) -> R) -> (A) -> (B) -> R { 12 | return { a in { b in f(a, b) } } 13 | } 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode10.3 3 | 4 | script: 5 | - xcodebuild build -project ETBinding.xcodeproj -scheme ETBinding-iOS -configuration "Release" -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO 6 | - xcodebuild test -project ETBinding.xcodeproj -scheme ETBinding-iOS -configuration "Debug" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone X' 7 | -------------------------------------------------------------------------------- /Sources/ETBinding/LiveData/LiveStateData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiveStateData.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 15. 12. 2017. 6 | // Copyright © 2017 ETBinding. All rights reserved. 7 | // 8 | 9 | /// Wraps generic value from `LiveData` into `StateValue` that adds success and 10 | /// failure states. 11 | public class LiveStateData: LiveData> {} 12 | -------------------------------------------------------------------------------- /Sources/ETBinding/LiveData/StateValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StateValue.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 15. 12. 2017. 6 | // Copyright © 2017 ETBinding. All rights reserved. 7 | // 8 | 9 | /// Value with state added 10 | public enum StateValue { 11 | /// Success value 12 | case success(Value) 13 | /// Error for failured value 14 | case failure(Swift.Error) 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ETBinding/Observable/LifecycleState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LifecycleState.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 15. 12. 2017. 6 | // Copyright © 2017 ETBinding. All rights reserved. 7 | // 8 | 9 | /// Valid states of `LifecycleOwner` 10 | public enum LifecycleState { 11 | /// Indicates that `LifecycleOwner` is still alive 12 | case active 13 | /// Indicates that `LifecycleOwner` is already deallocated 14 | case destroyed 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ETBinding/LiveData/LiveOptionalStateData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiveOptionalStateData.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 07. 02. 2019. 6 | // Copyright © 2019 Etnetera. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Wraps generic value from `LiveData` into `StateValue` that adds success and 12 | /// failure states. 13 | public class LiveOptionalStateData: LiveData?> { 14 | public convenience init() { 15 | self.init(data: nil) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.etbinding 7 | CFBundleName 8 | ETBinding 9 | DocSetPlatformFamily 10 | etbinding 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.etlivedata 7 | CFBundleName 8 | ETLiveData 9 | DocSetPlatformFamily 10 | etlivedata 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcbaselines/52D6D9851BEFF229002C0205.xcbaseline/38D69606-11F5-4043-B894-0F850F690971.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | PerformanceTests 8 | 9 | testPerformanceExample() 10 | 11 | com.apple.XCTPerformanceMetric_WallClockTime 12 | 13 | baselineAverage 14 | 0.25544 15 | baselineIntegrationDisplayName 16 | 6 Mar 2018 at 07:07:37 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ETBinding.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ETBinding" 3 | s.version = "3.4" 4 | s.summary = "ETBinding" 5 | s.description = <<-DESC 6 | ETBinding is set of observable classes. Unlike a regular observable is lifecycle-aware, meaning it respects the lifecycle of its owner. 7 | DESC 8 | s.homepage = "https://github.com/EtneteraMobile/ETBinding" 9 | s.license = { :type => "MIT", :file => "LICENSE" } 10 | s.author = { "Jan Cislinsky" => "jan.cislinsky@etnetera.cz" } 11 | s.social_media_url = "" 12 | s.ios.deployment_target = "11.0" 13 | s.source = { :git => "https://github.com/EtneteraMobile/ETBinding.git", :tag => s.version.to_s } 14 | s.source_files = "Sources/**/*" 15 | s.frameworks = "Foundation" 16 | end 17 | -------------------------------------------------------------------------------- /Configs/ETBindingTests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "ETBinding", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "ETBinding", 12 | targets: ["ETBinding"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 21 | .target( 22 | name: "ETBinding", 23 | dependencies: []), 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /Configs/ETBinding.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2017 Jan Cislinsky. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Sources/ETBinding/LiveData/LiveOptionalData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiveOptionalData.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 07. 02. 2019. 6 | // Copyright © 2019 Etnetera. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// `LiveData` is an observable data holder class. Unlike a regular observable, 12 | /// `LiveData` is lifecycle-aware, meaning it respects the lifecycle of its owner. 13 | /// This awareness ensures `LiveData` only updates app component observers that 14 | /// are in an active lifecycle state. 15 | /// 16 | /// let liveData = LiveData(data: "Initial") 17 | /// let observer = liveData.observeForever { (data) in 18 | /// print("\(String(describing: data))") 19 | /// } 20 | /// liveData.dispatch() 21 | /// // prints Initial 22 | /// liveData.data = "1" 23 | /// // prints 1 24 | /// liveData.remove(observer: observer) 25 | /// liveData.data = "2" 26 | /// // … nothing 27 | public class LiveOptionalData: LiveData { 28 | public convenience init() { 29 | self.init(data: nil) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/ETBinding/Helpers/DeallocTracker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeallocTracker.swift 3 | // ETBinding 4 | // 5 | // Created by Jan Čislinský on 05. 03. 2018. 6 | // Copyright © 2018 Etnetera. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class DeallocTracker { 12 | let onDealloc: () -> Void 13 | 14 | init(onDealloc: @escaping () -> Void) { 15 | self.onDealloc = onDealloc 16 | } 17 | 18 | deinit { 19 | onDealloc() 20 | } 21 | } 22 | 23 | /// Executes action upon deallocation of owner 24 | /// 25 | /// - Parameters: 26 | /// - owner: Owner to track. 27 | /// - closure: Closure to execute. 28 | public func onDealloc(of owner: Any, closure: @escaping () -> Void) { 29 | while true { 30 | // Generates random key for association and checks that it wasn't used already 31 | if let key = UnsafeRawPointer(bitPattern: UInt(arc4random())), objc_getAssociatedObject(owner, key) == nil { 32 | let tracker = DeallocTracker(onDealloc: closure) 33 | objc_setAssociatedObject(owner, key, tracker, .OBJC_ASSOCIATION_RETAIN) 34 | break 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jan Cislinsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 89% 23 | 24 | 25 | 89% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 89% 23 | 24 | 25 | 89% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 100% 23 | 24 | 25 | 100% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Sources/ETBinding/Observable/Observer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observer.swift 3 | // 4 | // Created by Jan Čislinský on 15. 12. 2017. 5 | // Copyright © 2017 Etnetera. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | /// `Observer` wrapps update closure. 11 | /// 12 | /// Class adds identity to closure. Implements `Hashable` that uses generated or injected `hashValue` as identifier. 13 | public class Observer: Hashable { 14 | /// Update closure 15 | public let update: (T) -> Void 16 | /// Identity identifier 17 | public let identity: Int 18 | 19 | /// Initializes `Observer` with given identity/hashValue and update closure. 20 | /// 21 | /// - Parameters: 22 | /// - identity: Identity of observer. If is nil then is generated. 23 | /// - update: Update closure. 24 | public init(identity: Int? = nil, update: @escaping (T) -> Void) { 25 | self.identity = identity ?? UUID().uuidString.hashValue 26 | self.update = update 27 | } 28 | 29 | public func hash(into hasher: inout Hasher) { 30 | hasher.combine(identity) 31 | } 32 | 33 | /// `Observer` equal comparator 34 | public static func ==(lhs: Observer, rhs: Observer) -> Bool { 35 | return lhs.hashValue == rhs.hashValue 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcbaselines/52D6D9851BEFF229002C0205.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | 38D69606-11F5-4043-B894-0F850F690971 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 100 13 | cpuCount 14 | 1 15 | cpuKind 16 | Intel Core i7 17 | cpuSpeedInMHz 18 | 2600 19 | logicalCPUCoresPerPackage 20 | 8 21 | modelCode 22 | MacBookPro13,3 23 | physicalCPUCoresPerPackage 24 | 4 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone10,3 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sources/ETBinding/Observable/LifecycleBoundObserver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LifecycleBoundObserver.swift 3 | // 4 | // Created by Jan Čislinský on 15. 12. 2017. 5 | // Copyright © 2017 Etnetera. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Lifecycle object for which is observer bound to 11 | public typealias LifecycleOwner = AnyObject 12 | 13 | /// Wrapper for `Observer` and `LifecycleOwner` whose state determines that 14 | /// `Observer` has to be active or not according lifecycle of owner. 15 | class LifecycleBoundObserver: Hashable { 16 | /// Lifecycle state of owner if was set in init otherwise returns forever `.active` 17 | var state: LifecycleState { 18 | get { 19 | return owner != nil || isActiveForever ? .active : .destroyed 20 | } 21 | } 22 | /// Observers that delivers updates 23 | let observer: Observer 24 | /// Last version of delivered data to observer 25 | var lastVersion: Int = Constants.startVersion 26 | 27 | weak var owner: LifecycleOwner? 28 | private let isActiveForever: Bool 29 | 30 | init(owner: LifecycleOwner? = nil, observer: Observer) { 31 | self.owner = owner 32 | self.observer = observer 33 | self.isActiveForever = owner == nil 34 | } 35 | 36 | func hash(into hasher: inout Hasher) { 37 | hasher.combine(observer.hashValue) 38 | } 39 | 40 | static func ==(lhs: LifecycleBoundObserver, rhs: LifecycleBoundObserver) -> Bool { 41 | return lhs.hashValue == rhs.hashValue 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/ETBindingTests/PerformanceTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PerformanceTests.swift 3 | // ETBinding-iOS Tests 4 | // 5 | // Created by Jan Čislinský on 06. 03. 2018. 6 | // Copyright © 2018 Etnetera. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import ETBinding 11 | 12 | class PerformanceTests: XCTestCase { 13 | private var owner: LifecycleOwner? = Owner() 14 | private var observable: LiveData! 15 | 16 | override func setUp() { 17 | super.setUp() 18 | owner = Owner() 19 | observable = LiveData() 20 | } 21 | 22 | func onUpdate(_ input: String?) {} 23 | 24 | func testPerformanceExample() { 25 | self.measure { 26 | let queue = DispatchQueue(label: "tests", qos: .userInitiated, attributes: .concurrent) 27 | let group = DispatchGroup() 28 | 29 | for _ in 0..<10000 { 30 | group.enter() 31 | let observer = Observer(update: self.onUpdate) 32 | let add = DispatchWorkItem(block: { 33 | self.observable.observe(owner: self.owner!, observer: observer) 34 | }) 35 | let remove = DispatchWorkItem(block: { 36 | add.wait() 37 | self.observable.remove(observer: observer) 38 | group.leave() 39 | }) 40 | 41 | queue.async(execute: add) 42 | queue.async(execute: remove) 43 | } 44 | 45 | group.wait() 46 | } 47 | } 48 | } 49 | 50 | private class Owner {} 51 | -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | 52 | Carthage/Checkouts 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output 66 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/FutureEvent/FutureEvent.swift", 5 | "line": 27, 6 | "symbol": "FutureEvent.DataType", 7 | "symbol_kind": "source.lang.swift.decl.typealias", 8 | "warning": "undocumented" 9 | }, 10 | { 11 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/FutureEvent/FutureEvent.swift", 12 | "line": 49, 13 | "symbol": "FutureEvent.init()", 14 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 15 | "warning": "undocumented" 16 | }, 17 | { 18 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/LiveData/LiveData.swift", 19 | "line": 28, 20 | "symbol": "LiveData.DataType", 21 | "symbol_kind": "source.lang.swift.decl.typealias", 22 | "warning": "undocumented" 23 | }, 24 | { 25 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/Observable/Observable.swift", 26 | "line": 12, 27 | "symbol": "Observable.DataType", 28 | "symbol_kind": "source.lang.swift.decl.associatedtype", 29 | "warning": "undocumented" 30 | }, 31 | { 32 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/Observable/SingleEventObservable.swift", 33 | "line": 12, 34 | "symbol": "SingleEventObservable.DataType", 35 | "symbol_kind": "source.lang.swift.decl.associatedtype", 36 | "warning": "undocumented" 37 | }, 38 | { 39 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/SingleEvent/SingleEvent.swift", 40 | "line": 29, 41 | "symbol": "SingleEvent.DataType", 42 | "symbol_kind": "source.lang.swift.decl.typealias", 43 | "warning": "undocumented" 44 | }, 45 | { 46 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/SingleEvent/SingleEvent.swift", 47 | "line": 56, 48 | "symbol": "SingleEvent.init()", 49 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 50 | "warning": "undocumented" 51 | } 52 | ], 53 | "source_directory": "/Users/jancislinsky/Repos/iOS/ETBinding" 54 | } -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/FutureEvent/FutureEvent.swift", 5 | "line": 27, 6 | "symbol": "FutureEvent.DataType", 7 | "symbol_kind": "source.lang.swift.decl.typealias", 8 | "warning": "undocumented" 9 | }, 10 | { 11 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/FutureEvent/FutureEvent.swift", 12 | "line": 49, 13 | "symbol": "FutureEvent.init()", 14 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 15 | "warning": "undocumented" 16 | }, 17 | { 18 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/LiveData/LiveData.swift", 19 | "line": 28, 20 | "symbol": "LiveData.DataType", 21 | "symbol_kind": "source.lang.swift.decl.typealias", 22 | "warning": "undocumented" 23 | }, 24 | { 25 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/Observable/Observable.swift", 26 | "line": 12, 27 | "symbol": "Observable.DataType", 28 | "symbol_kind": "source.lang.swift.decl.associatedtype", 29 | "warning": "undocumented" 30 | }, 31 | { 32 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/Observable/SingleEventObservable.swift", 33 | "line": 12, 34 | "symbol": "SingleEventObservable.DataType", 35 | "symbol_kind": "source.lang.swift.decl.associatedtype", 36 | "warning": "undocumented" 37 | }, 38 | { 39 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/SingleEvent/SingleEvent.swift", 40 | "line": 29, 41 | "symbol": "SingleEvent.DataType", 42 | "symbol_kind": "source.lang.swift.decl.typealias", 43 | "warning": "undocumented" 44 | }, 45 | { 46 | "file": "/Users/jancislinsky/Repos/iOS/ETBinding/Sources/SingleEvent/SingleEvent.swift", 47 | "line": 56, 48 | "symbol": "SingleEvent.init()", 49 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 50 | "warning": "undocumented" 51 | } 52 | ], 53 | "source_directory": "/Users/jancislinsky/Repos/iOS/ETBinding" 54 | } -------------------------------------------------------------------------------- /Sources/ETBinding/Observable/Observable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observable.swift 3 | // 4 | // Created by Jan Čislinský on 04. 03. 2018. 5 | // Copyright © 2018 Etnetera. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Declares methods for observation. 11 | public protocol Observable: class { 12 | associatedtype DataType 13 | 14 | /// Starts observation until given owner is alive or `remove(observer:)` is called. 15 | /// 16 | /// - Attention: 17 | /// - After deallocation of owner `onUpdate` will be never called. 18 | /// 19 | /// - Parameters: 20 | /// - owner: LifecycleOwner of newly created observation. 21 | /// - onUpdate: Closure that is called on change. 22 | /// 23 | /// - Returns: Observer that represents update block. 24 | @discardableResult func observe(owner: LifecycleOwner, onUpdate: @escaping (DataType) -> Void) -> Observer 25 | 26 | /// Starts observation until given owner is alive or `remove(observer:)` is called. 27 | /// 28 | /// - Requires: Given `observer` can be registered only once. 29 | /// 30 | /// - Attention: 31 | /// - After deallocation of owner `observer.update` will be never called. 32 | /// 33 | /// - Parameters: 34 | /// - owner: LifecycleOwner of newly created observation. 35 | /// - observer: Observer that is updated on every `data` change. 36 | func observe(owner: LifecycleOwner, observer: Observer) 37 | 38 | /// Starts observation until `remove(observer:)` called. 39 | /// 40 | /// - Parameters: 41 | /// - onUpdate: Closure that is called on `data` change. 42 | /// 43 | /// - Returns: Observer that represents update block. 44 | func observeForever(onUpdate: @escaping (DataType) -> Void) -> Observer 45 | 46 | /// Starts observation until `remove(observer:)` called. 47 | /// 48 | /// - Requires: Given `observer` can be registered only once. 49 | /// 50 | /// - Parameters: 51 | /// - observer: Observer that is updated on every `data` change. 52 | func observeForever(observer: Observer) 53 | 54 | /// Unregister given `observer` from observation. 55 | /// 56 | /// - Parameter observer: Observer that has to be removed 57 | /// - Returns: `True` if observer was unregistered or `false` if observer 58 | /// wasn't never registered. 59 | @discardableResult func remove(observer: Observer) -> Bool 60 | } 61 | -------------------------------------------------------------------------------- /Sources/ETBindingTests/LiveStateDataTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiveOptionalStateDataTests.swift 3 | // 4 | // Created by Jan Cislinsky on 15. 12. 2017. 5 | // Copyright © 2017 ETBinding. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import XCTest 10 | import ETBinding 11 | 12 | class LiveOptionalStateDataTests: XCTestCase { 13 | 14 | var expectations: [XCTestExpectation]! 15 | var liveData: LiveOptionalStateData! 16 | 17 | override func setUp() { 18 | super.setUp() 19 | liveData = LiveOptionalStateData() 20 | } 21 | 22 | func onUpdate(_ input: String?) { 23 | guard expectations.isEmpty == false else { 24 | XCTAssert(expectations.isEmpty == false, "Update called more than expected") 25 | return 26 | } 27 | XCTAssert(input == expectations[0].expectationDescription, "Observer receives invalid data") 28 | expectations[0].fulfill() 29 | expectations.removeFirst() 30 | } 31 | 32 | // MARK: - 33 | 34 | func testSuccessState() { 35 | let str = "New data" 36 | let exp = expectation(description: str) 37 | let observer = Observer?>(update: { data in 38 | XCTAssertNotNil(data) 39 | if case .success(let value) = data! { 40 | XCTAssert(value == str) 41 | } else { 42 | XCTFail() 43 | } 44 | exp.fulfill() 45 | }) 46 | 47 | liveData.observeForever(observer: observer) 48 | liveData.data = .success(str) 49 | 50 | waitForExpectations(timeout: 10, handler: nil) 51 | } 52 | 53 | func testFailureState() { 54 | let str = "New data" 55 | let exp = expectation(description: str) 56 | let observer = Observer?>(update: { data in 57 | XCTAssertNotNil(data) 58 | if case .failure(let error) = data! { 59 | if let err = error as? TestError { 60 | XCTAssert(err == .test) 61 | } else { 62 | XCTFail() 63 | } 64 | } else { 65 | XCTFail() 66 | } 67 | exp.fulfill() 68 | }) 69 | 70 | liveData.observeForever(observer: observer) 71 | liveData.data = .failure(TestError.test) 72 | 73 | waitForExpectations(timeout: 10, handler: nil) 74 | 75 | } 76 | 77 | static var allTests = [ 78 | ("testFailureState", testFailureState), 79 | ("testSuccessState", testSuccessState), 80 | ] 81 | } 82 | 83 | enum TestError: Swift.Error { 84 | case test 85 | } 86 | 87 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcschemes/ETBinding-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcschemes/ETBinding-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcschemes/ETBinding-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /ETBinding.xcodeproj/xcshareddata/xcschemes/ETBinding-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/search.json: -------------------------------------------------------------------------------- 1 | {"Enums/StateValue.html#/s:10ETLiveData10StateValueO7successACyxGxcAEmlF":{"name":"success","abstract":"

Success value

","parent_name":"StateValue"},"Enums/StateValue.html#/s:10ETLiveData10StateValueO7failureACyxGs5Error_pcAEmlF":{"name":"failure","abstract":"

Error for failured value

","parent_name":"StateValue"},"Enums/LifecycleState.html#/s:10ETLiveData14LifecycleStateO6activeA2CmF":{"name":"active","abstract":"

Indicates that LifecycleOwner is still alive

","parent_name":"LifecycleState"},"Enums/LifecycleState.html#/s:10ETLiveData14LifecycleStateO9destroyedA2CmF":{"name":"destroyed","abstract":"

Indicates that LifecycleOwner is already deallocated

","parent_name":"LifecycleState"},"Enums/LifecycleState.html":{"name":"LifecycleState","abstract":"

Valid states of LifecycleOwner

"},"Enums/StateValue.html":{"name":"StateValue","abstract":"

Value with state added

"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C4dataxSgv":{"name":"data","abstract":"

The current value that is dispatched after assignment.

","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0CACyxGxSg4data_tcfc":{"name":"init(data:)","abstract":"

Initializes LiveData with given data.

","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C7observe10ETObserver8ObserverCyxSgGyXl5owner_yAHc8onUpdatetF":{"name":"observe(owner:onUpdate:)","abstract":"

Starts observing changes of data until given owner is alive or","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C7observeyyXl5owner_10ETObserver8ObserverCyxSgG8observertF":{"name":"observe(owner:observer:)","abstract":"

Starts observing changes of data until given owner is alive or","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C14observeForever10ETObserver8ObserverCyxSgGyAHc8onUpdate_tF":{"name":"observeForever(onUpdate:)","abstract":"

Starts observing changes of data until remove(observer:) called.

","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C14observeForever10ETObserver8ObserverCyxSgGAI8observer_tF":{"name":"observeForever(observer:)","abstract":"

Starts observing changes of data until remove(observer:) called.

","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C6removeSb10ETObserver8ObserverCyxSgG8observer_tF":{"name":"remove(observer:)","abstract":"

Unregister given observer from data observation.

","parent_name":"LiveData"},"Classes/LiveData.html#/s:10ETLiveData04LiveB0C8dispatchy10ETObserver8ObserverCyxSgGSg9initiator_tF":{"name":"dispatch(initiator:)","abstract":"

Dispatches current value to observers that don’t have it still.

","parent_name":"LiveData"},"Classes.html#/s:10ETLiveData09LiveStateB0C":{"name":"LiveStateData","abstract":"

Wraps generic value from LiveData into StateValue that adds success and"},"Classes/LiveData.html":{"name":"LiveData","abstract":"

LiveData is an observable data holder class. Unlike a regular observable,"},"Classes.html":{"name":"Classes","abstract":"

The following classes are available globally.

"},"Enums.html":{"name":"Enumerations","abstract":"

The following enumerations are available globally.

"}} -------------------------------------------------------------------------------- /docs/Structs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Structures Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ETLiveData Docs (86% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 72 |
73 |
74 |
75 |

Structures

76 |

The following structures are available globally.

77 | 78 |
79 |
80 |
81 |
    82 |
  • 83 |
    84 | 85 | 86 | 87 | FatalErrorUtil 88 | 89 |
    90 |
    91 |
    92 |
    93 |
    94 |
    95 |

    Utility functions that can replace and restore the fatalError global function.

    96 | 97 | See more 98 |
    99 |
    100 |

    Declaration

    101 |
    102 |

    Swift

    103 |
    public struct FatalErrorUtil
    104 | 105 |
    106 |
    107 |
    108 |
    109 |
  • 110 |
111 |
112 |
113 |
114 | 118 |
119 |
120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Structs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Structures Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ETLiveData Docs (86% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 72 |
73 |
74 |
75 |

Structures

76 |

The following structures are available globally.

77 | 78 |
79 |
80 |
81 |
    82 |
  • 83 |
    84 | 85 | 86 | 87 | FatalErrorUtil 88 | 89 |
    90 |
    91 |
    92 |
    93 |
    94 |
    95 |

    Utility functions that can replace and restore the fatalError global function.

    96 | 97 | See more 98 |
    99 |
    100 |

    Declaration

    101 |
    102 |

    Swift

    103 |
    public struct FatalErrorUtil
    104 | 105 |
    106 |
    107 |
    108 |
    109 |
  • 110 |
111 |
112 |
113 |
114 | 118 |
119 |
120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/Structs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Structures Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ETLiveData Docs (86% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 72 |
73 |
74 |
75 |

Structures

76 |

The following structures are available globally.

77 | 78 |
79 |
80 |
81 |
    82 |
  • 83 |
    84 | 85 | 86 | 87 | FatalErrorUtil 88 | 89 |
    90 |
    91 |
    92 |
    93 |
    94 |
    95 |

    Utility functions that can replace and restore the fatalError global function.

    96 | 97 | See more 98 |
    99 |
    100 |

    Declaration

    101 |
    102 |

    Swift

    103 |
    public struct FatalErrorUtil
    104 | 105 |
    106 |
    107 |
    108 |
    109 |
  • 110 |
111 |
112 |
113 |
114 | 118 |
119 |
120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enumerations Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ETLiveData Docs (100% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 53 |
54 |
55 |
56 |

Enumerations

57 |

The following enumerations are available globally.

58 | 59 |
60 |
61 |
62 |
    63 |
  • 64 |
    65 | 66 | 67 | 68 | LifecycleState 69 | 70 |
    71 |
    72 |
    73 |
    74 |
    75 |
    76 |

    Valid states of LifecycleOwner

    77 | 78 | See more 79 |
    80 |
    81 |

    Declaration

    82 |
    83 |

    Swift

    84 |
    public enum LifecycleState
    85 | 86 |
    87 |
    88 |
    89 |
    90 |
  • 91 |
92 |
93 |
94 |
    95 |
  • 96 |
    97 | 98 | 99 | 100 | StateValue 101 | 102 |
    103 |
    104 |
    105 |
    106 |
    107 |
    108 |

    Value with state added

    109 | 110 | See more 111 |
    112 |
    113 |

    Declaration

    114 |
    115 |

    Swift

    116 |
    public enum StateValue<Value>
    117 | 118 |
    119 |
    120 |
    121 |
    122 |
  • 123 |
124 |
125 |
126 |
127 | 131 |
132 |
133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /docs/Typealiases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Aliases Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Type Aliases

94 |

The following type aliases are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | LifecycleOwner 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Lifecycle object for which is observer bound to

    114 | 115 |
    116 |
    117 |

    Declaration

    118 |
    119 |

    Swift

    120 |
    public typealias LifecycleOwner = AnyObject
    121 | 122 |
    123 |
    124 |
    125 |
    126 |
  • 127 |
128 |
129 |
130 |
131 | 135 |
136 |
137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Typealiases.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Type Aliases Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Type Aliases

94 |

The following type aliases are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | LifecycleOwner 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Lifecycle object for which is observer bound to

    114 | 115 |
    116 |
    117 |

    Declaration

    118 |
    119 |

    Swift

    120 |
    public typealias LifecycleOwner = AnyObject
    121 | 122 |
    123 |
    124 |
    125 |
    126 |
  • 127 |
128 |
129 |
130 |
131 | 135 |
136 |
137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/Enums/LifecycleState.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LifecycleState Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETLiveData Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 54 |
55 |
56 |
57 |

LifecycleState

58 |
59 |
60 |
public enum LifecycleState
61 | 62 |
63 |
64 |

Valid states of LifecycleOwner

65 | 66 |
67 |
68 |
69 |
    70 |
  • 71 |
    72 | 73 | 74 | 75 | active 76 | 77 |
    78 |
    79 |
    80 |
    81 |
    82 |
    83 |

    Indicates that LifecycleOwner is still alive

    84 | 85 |
    86 |
    87 |

    Declaration

    88 |
    89 |

    Swift

    90 |
    case active
    91 | 92 |
    93 |
    94 |
    95 |
    96 |
  • 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | destroyed 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    Indicates that LifecycleOwner is already deallocated

    115 | 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    case destroyed
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
132 | 136 |
137 |
138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/Enums/StateValue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | StateValue Enumeration Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETLiveData Docs (100% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 54 |
55 |
56 |
57 |

StateValue

58 |
59 |
60 |
public enum StateValue<Value>
61 | 62 |
63 |
64 |

Value with state added

65 | 66 |
67 |
68 |
69 |
    70 |
  • 71 |
    72 | 73 | 74 | 75 | success 76 | 77 |
    78 |
    79 |
    80 |
    81 |
    82 |
    83 |

    Success value

    84 | 85 |
    86 |
    87 |

    Declaration

    88 |
    89 |

    Swift

    90 |
    case success(Value)
    91 | 92 |
    93 |
    94 |
    95 |
    96 |
  • 97 |
98 |
99 |
100 |
    101 |
  • 102 |
    103 | 104 | 105 | 106 | failure 107 | 108 |
    109 |
    110 |
    111 |
    112 |
    113 |
    114 |

    Error for failured value

    115 | 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    case failure(Swift.Error)
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
132 | 136 |
137 |
138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Binding for iOS 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/ETLiveData.svg?style=flat)](http://cocoapods.org/pods/ETLiveData) 4 | [![License](https://img.shields.io/cocoapods/l/ETLiveData.svg?style=flat)](http://cocoapods.org/pods/ETLiveData) 5 | [![Platform](https://img.shields.io/cocoapods/p/ETLiveData.svg?style=flat)](http://cocoapods.org/pods/ETLiveData) 6 | [![Build Status](https://travis-ci.org/EtneteraMobile/ETBinding.svg?branch=master)](https://travis-ci.org/EtneteraMobile/ETBinding) 7 | 8 | 9 | 10 | *Inspired by [LiveData](https://developer.android.com/topic/libraries/architecture/livedata.html) from Android Architecture Components.* 11 | 12 | ------ 13 | 14 | ## Observable concept 15 | 16 | There are three classes that can be observed: `LiveData`, `FutureEvent` and `SingleEvent`. 17 | 18 | `LiveData` and `FutureEvent` implements `Observable` protocol. `SingleEvent` is special case of `FutureEvent` and implements `SingleEventObservable` protocol. 19 | 20 | Unlike a regular observation pattern, `Observable` (and `SingleEventObservable`) is lifecycle-aware, meaning it respects the lifecycle of its owner. This awareness ensures `Observable` only updates app component observers that are in an active lifecycle state. 21 | 22 | You can register an observer paired with an object that is `LifecycleOwner` (typealias for AnyObject). This relationship allows the observer to be removed when the state of the corresponding `LifecycleOwner` changes to deallocated. This is especially useful for view controllers because they can safely observe objects from view model and not worry about leaks. 23 | 24 | #### When to use `LiveData`, `FutureEvent` and `SingleEvent` 25 | 26 | - `LiveData` – holds state/data. State changes can be observed. 27 | - `FutureEvent` – doesn't hold state, just notify observers when event is triggered. Event can has associated value. 28 | - `SingleEvent` – is special case of `FutureEvent`. Delivers only the first triggered event. 29 | 30 | ## Advantages 31 | 32 | ### No memory leaks 33 | 34 | Observers are bound to lifecycle objects and clean up after themselves when their associated lifecycle is destroyed. 35 | 36 | ### Safe [unowned self] 37 | 38 | Because Observer is bound to lifecycle, it will never happens that observer is updated if `LifecycleOwner` is deallocated. 39 | 40 | ### No more manual lifecycle handling 41 | 42 | UI components just observe relevant data and don’t stop observation. `Observable` automatically manages this since it’s aware of the relevant lifecycle status changes while observing. 43 | 44 | ## Installation 45 | 46 | ### CocoaPods 47 | 48 | Add `pod 'ETBinding'` to your Podfile. 49 | 50 | ### Carthage 51 | 52 | Add `github "EtneteraMobile/ETBinding"` to your Cartfile. 53 | 54 | ### Swift Package Manager 55 | 56 | In Xcode (>11.0) go to File -> Swift Packages -> Add Package Dependency. There insert `https://github.com/EtneteraMobile/ETBinding` in URL input and finish importing `ETBinding` to your project. 57 | 58 | ## Usage 59 | 60 | Follow these steps to work with `LiveData` objects: 61 | 62 | 1. Create an instance of `LiveData` to hold a certain type of data. This is usually done within your ViewModel class. 63 | 2. Create an `Observer` object that defines the update closure, which controls what happens when the `LiveData` object's held data changes. You usually create an `Observer` object in a view controller. 64 | 3. Attach the `Observer` object to the `LiveData` object using the `observe` method. The `observe` method takes a `LifecycleOwner` object. This subscribes the `Observer` object to the `LiveData` object so that it is notified of changes. 65 | 66 | **Note:** You can register an observer without an associated `LifecycleOwner` object using the [`observeForever`](#observe-forever) method. In this case, the observer is considered to be always active and is therefore always notified about modifications. You can remove these observers calling the [`removeObserver`](#remove-observer) method. 67 | 68 | When you update the value stored in the `LiveData` object, it triggers all registered observers as long as the attached `LifecycleOwner` is in the active state. 69 | 70 | ### Observe with lifecycle owner 71 | 72 | Observation starts only with owner and update closure, then new instance of `Observer` is returned. This observer can be ignored in case when future remove isn't needed. 73 | 74 | ```swift 75 | let liveData: LiveData = LiveData() 76 | let observer = liveData.observe(owner: self) { data in 77 | // do something with data 78 | } 79 | // observer can be used for later unregistration 80 | ``` 81 | 82 | Update closure can be encapsulated inside `Observer` and after then registered. This pattern could be used when observation will be started in future. 83 | 84 | ```swift 85 | let observer: Observer = Observer(update: { data in 86 | // do something with data 87 | }) 88 | // … and later 89 | let liveData: LiveData = LiveData() 90 | liveData.observe(owner: self, observer: observer) 91 | // observer can be used for later unregistration 92 | ``` 93 | 94 | ### Observe forever 95 | 96 | Lifecycle owner isn't mandatory all the time. When owner isn't given, unregistration is under your control. 97 | 98 | ```swift 99 | let liveData: LiveData = LiveData() 100 | let observer = liveData.observeForever { data in 101 | // do something with data 102 | } 103 | // observer can be used for later unregistration 104 | ``` 105 | 106 | ```swift 107 | let observer: Observer = Observer(update: { data in 108 | // do something with data 109 | }) 110 | // … and later 111 | let liveData: LiveData = LiveData() 112 | liveData.observeForever(observer: observer) 113 | // observer can be used for later unregistration 114 | ``` 115 | 116 | ### Remove observer 117 | 118 | Unregisters given observer from liveData changes observation. 119 | 120 | ```swift 121 | // … observer is obtained from early called function `observe` 122 | liveData.remove(observer: observer) 123 | ``` 124 | 125 | ### Dispatch value to observers 126 | 127 | After observation is started value isn't automatically dispatched to observer. If you want to gain current value, you can read it directly from `data` variable or you can call `dispatch` and update will be delivered to newly registered observers. 128 | 129 | ```swift 130 | // Dispatches value to observers that were registered from last dispatch 131 | liveData.dispatch() 132 | 133 | // Dispatches value to given observer if is newly registered from last dispatch 134 | liveData.dispatch(initiator: observer) 135 | ``` 136 | 137 | Every **observer is called only once per new value although `dispatch` is called multiple times**. Value setter is versioned and observer holds last delivered value version and blocks dispatching of version that was already delivered. 138 | 139 | ## Contributing 140 | 141 | Contributions to ETBinding are welcomed and encouraged! 142 | 143 | ## License 144 | 145 | ETBinding is available under the MIT license. See [LICENSE](LICENSE) for more information. 146 | 147 | ## Attributions 148 | 149 | I've used [SwiftPlate](https://github.com/JohnSundell/SwiftPlate) to generate xcodeproj compatible with CocoaPods and Carthage. 150 | -------------------------------------------------------------------------------- /Sources/ETBinding/FutureEvent/FutureEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FutureEvent.swift 3 | // 4 | // Created by Jan Čislinský on 05. 03. 2018. 5 | // Copyright © 2018 Etnetera. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | /// `FutureEvent` is an observable event handler class. Unlike a regular observable, 11 | /// `FutureEvent` is lifecycle-aware, meaning it respects the lifecycle of its owner. 12 | /// This awareness ensures `FutureEvent` only triggers app component observers that 13 | /// are in an active lifecycle state. 14 | /// 15 | /// let onPress = FutureEvent() 16 | /// let observer = onPress.observeForever { 17 | /// print("Button pressed") 18 | /// } 19 | /// onPress.trigger() 20 | /// // prints Button pressed 21 | /// 22 | /// onPress.remove(observer: observer) 23 | /// 24 | /// onPress.trigger() 25 | /// // … nothing 26 | public class FutureEvent: Observable, CustomStringConvertible { 27 | public typealias DataType = Action 28 | 29 | // MARK: - Variables 30 | // MARK: public 31 | 32 | public var description: String { 33 | let observersDesc = observers.reduce("") { accum, current in 34 | let desc = "\tid: \(current.hashValue), ownerState: \(current.state), owner: \(String(describing: current.owner))\n" 35 | return accum + desc 36 | } 37 | return """ 38 | observers:\n\(observersDesc)) 39 | """ 40 | } 41 | 42 | // MARK: internal 43 | 44 | var observers: Set> = [] 45 | 46 | // MARK: - Initialization 47 | 48 | public init() {} 49 | } 50 | 51 | public extension FutureEvent { 52 | // MARK: - Observe 53 | 54 | /// Starts observation until given owner is alive or `remove(observer:)` is called. 55 | /// 56 | /// - Attention: 57 | /// - After deallocation of owner `onUpdate` will be never called. 58 | /// - Inside of `onUpdate` closure you are alway on main thread. 59 | /// 60 | /// - Parameters: 61 | /// - owner: LifecycleOwner of newly created observation. 62 | /// - onUpdate: Closure that is called on change. 63 | /// 64 | /// - Returns: Observer that represents update block. 65 | @discardableResult func observe(owner: LifecycleOwner, onUpdate: @escaping (DataType) -> Void) -> Observer { 66 | let wrapper = LifecycleBoundObserver(owner: owner, observer: Observer(update: onUpdate)) 67 | return observe(wrapper) 68 | } 69 | 70 | /// Starts observation until given owner is alive or `remove(observer:)` is called. 71 | /// 72 | /// - Requires: Given `observer` can be registered only once. 73 | /// 74 | /// - Attention: 75 | /// - After deallocation of owner `observer.update` will be never called. 76 | /// - Inside of `observer.update` closure you are alway on main thread. 77 | /// 78 | /// - Parameters: 79 | /// - owner: LifecycleOwner of newly created observation. 80 | /// - observer: Observer that is updated on every `data` change. 81 | func observe(owner: LifecycleOwner, observer: Observer) { 82 | let wrapper = LifecycleBoundObserver(owner: owner, observer: observer) 83 | observe(wrapper) 84 | } 85 | 86 | /// Starts observation until `remove(observer:)` called. 87 | /// 88 | /// - Parameters: 89 | /// - onUpdate: Closure that is called on `data` change. 90 | /// - Inside of `onUpdate` closure you are alway on main thread. 91 | /// 92 | /// - Returns: Observer that represents update block. 93 | @discardableResult func observeForever(onUpdate: @escaping (DataType) -> Void) -> Observer { 94 | let wrapper = LifecycleBoundObserver(observer: Observer(update: onUpdate)) 95 | return observe(wrapper) 96 | } 97 | 98 | /// Starts observation until `remove(observer:)` called. 99 | /// 100 | /// - Requires: Given `observer` can be registered only once. 101 | /// 102 | /// - Attention: 103 | /// - Inside of `observer.update` closure you are alway on main thread. 104 | /// 105 | /// - Parameters: 106 | /// - observer: Observer that is updated on every `data` change. 107 | func observeForever(observer: Observer) { 108 | let wrapper = LifecycleBoundObserver(observer: observer) 109 | observe(wrapper) 110 | } 111 | 112 | // MARK: - Remove 113 | 114 | /// Unregister given `observer` from observation. 115 | /// 116 | /// - Parameter observer: Observer that has to be removed 117 | /// - Returns: `True` if observer was unregistered or `false` if observer 118 | /// wasn't never registered. 119 | @discardableResult func remove(observer: Observer) -> Bool { 120 | func onMainQueue() -> Bool { 121 | let existingIdx = observers.firstIndex { (rhs) -> Bool in 122 | observer.hashValue == rhs.observer.hashValue 123 | } 124 | if let idx = existingIdx { 125 | observers.remove(at: idx) 126 | return true 127 | } 128 | return false 129 | } 130 | return Thread.isMainThread ? onMainQueue() : DispatchQueue.main.sync(execute: onMainQueue) 131 | } 132 | } 133 | 134 | // MARK: - Trigger 135 | 136 | public extension FutureEvent where DataType == Void { 137 | /// Triggers observers. 138 | func trigger() { 139 | triggerObservers(()) 140 | } 141 | } 142 | 143 | public extension FutureEvent where DataType: Any { 144 | /// Triggers observers with given argument. 145 | /// 146 | /// - Parameters: 147 | /// - arg: Argument that is passed to observers. 148 | func trigger(_ arg: DataType) { 149 | triggerObservers(arg) 150 | } 151 | } 152 | 153 | private extension FutureEvent { 154 | @discardableResult func observe(_ wrapper: LifecycleBoundObserver) -> Observer { 155 | func onMainQueue() -> Observer { 156 | guard observers.contains(wrapper) == false else { 157 | fatalError("Unable to register same observer multiple time") 158 | } 159 | observers.insert(wrapper) 160 | 161 | // Removes observer on owner dealloc 162 | if let owner = wrapper.owner { 163 | onDealloc(of: owner) { [weak self, weak wrapper] in 164 | if let wrapper = wrapper { 165 | self?.remove(observer: wrapper.observer) 166 | } 167 | } 168 | } 169 | 170 | return wrapper.observer 171 | } 172 | return Thread.isMainThread ? onMainQueue() : DispatchQueue.main.sync(execute: onMainQueue) 173 | } 174 | 175 | func triggerObservers(_ arg: DataType) { 176 | func onMainQueue() { 177 | // Removes destroyed observers 178 | observers = observers.filter { 179 | $0.state != .destroyed 180 | } 181 | // Triggers all observers 182 | observers.forEach { 183 | $0.observer.update(arg) 184 | } 185 | } 186 | return Thread.isMainThread ? onMainQueue() : DispatchQueue.main.sync(execute: onMainQueue) 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Configs/iOS/ETObserver.framework/Headers/ETObserver-Swift.h: -------------------------------------------------------------------------------- 1 | // Generated by Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) 2 | #pragma clang diagnostic push 3 | #pragma clang diagnostic ignored "-Wgcc-compat" 4 | 5 | #if !defined(__has_include) 6 | # define __has_include(x) 0 7 | #endif 8 | #if !defined(__has_attribute) 9 | # define __has_attribute(x) 0 10 | #endif 11 | #if !defined(__has_feature) 12 | # define __has_feature(x) 0 13 | #endif 14 | #if !defined(__has_warning) 15 | # define __has_warning(x) 0 16 | #endif 17 | 18 | #if __has_attribute(external_source_symbol) 19 | # define SWIFT_STRINGIFY(str) #str 20 | # define SWIFT_MODULE_NAMESPACE_PUSH(module_name) _Pragma(SWIFT_STRINGIFY(clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in=module_name, generated_declaration))), apply_to=any(function, enum, objc_interface, objc_category, objc_protocol)))) 21 | # define SWIFT_MODULE_NAMESPACE_POP _Pragma("clang attribute pop") 22 | #else 23 | # define SWIFT_MODULE_NAMESPACE_PUSH(module_name) 24 | # define SWIFT_MODULE_NAMESPACE_POP 25 | #endif 26 | 27 | #if __has_include() 28 | # include 29 | #endif 30 | 31 | #pragma clang diagnostic ignored "-Wauto-import" 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #if !defined(SWIFT_TYPEDEFS) 38 | # define SWIFT_TYPEDEFS 1 39 | # if __has_include() 40 | # include 41 | # elif !defined(__cplusplus) || __cplusplus < 201103L 42 | typedef uint_least16_t char16_t; 43 | typedef uint_least32_t char32_t; 44 | # endif 45 | typedef float swift_float2 __attribute__((__ext_vector_type__(2))); 46 | typedef float swift_float3 __attribute__((__ext_vector_type__(3))); 47 | typedef float swift_float4 __attribute__((__ext_vector_type__(4))); 48 | typedef double swift_double2 __attribute__((__ext_vector_type__(2))); 49 | typedef double swift_double3 __attribute__((__ext_vector_type__(3))); 50 | typedef double swift_double4 __attribute__((__ext_vector_type__(4))); 51 | typedef int swift_int2 __attribute__((__ext_vector_type__(2))); 52 | typedef int swift_int3 __attribute__((__ext_vector_type__(3))); 53 | typedef int swift_int4 __attribute__((__ext_vector_type__(4))); 54 | typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); 55 | typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); 56 | typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); 57 | #endif 58 | 59 | #if !defined(SWIFT_PASTE) 60 | # define SWIFT_PASTE_HELPER(x, y) x##y 61 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) 62 | #endif 63 | #if !defined(SWIFT_METATYPE) 64 | # define SWIFT_METATYPE(X) Class 65 | #endif 66 | #if !defined(SWIFT_CLASS_PROPERTY) 67 | # if __has_feature(objc_class_property) 68 | # define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ 69 | # else 70 | # define SWIFT_CLASS_PROPERTY(...) 71 | # endif 72 | #endif 73 | 74 | #if __has_attribute(objc_runtime_name) 75 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) 76 | #else 77 | # define SWIFT_RUNTIME_NAME(X) 78 | #endif 79 | #if __has_attribute(swift_name) 80 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) 81 | #else 82 | # define SWIFT_COMPILE_NAME(X) 83 | #endif 84 | #if __has_attribute(objc_method_family) 85 | # define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) 86 | #else 87 | # define SWIFT_METHOD_FAMILY(X) 88 | #endif 89 | #if __has_attribute(noescape) 90 | # define SWIFT_NOESCAPE __attribute__((noescape)) 91 | #else 92 | # define SWIFT_NOESCAPE 93 | #endif 94 | #if __has_attribute(warn_unused_result) 95 | # define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) 96 | #else 97 | # define SWIFT_WARN_UNUSED_RESULT 98 | #endif 99 | #if __has_attribute(noreturn) 100 | # define SWIFT_NORETURN __attribute__((noreturn)) 101 | #else 102 | # define SWIFT_NORETURN 103 | #endif 104 | #if !defined(SWIFT_CLASS_EXTRA) 105 | # define SWIFT_CLASS_EXTRA 106 | #endif 107 | #if !defined(SWIFT_PROTOCOL_EXTRA) 108 | # define SWIFT_PROTOCOL_EXTRA 109 | #endif 110 | #if !defined(SWIFT_ENUM_EXTRA) 111 | # define SWIFT_ENUM_EXTRA 112 | #endif 113 | #if !defined(SWIFT_CLASS) 114 | # if __has_attribute(objc_subclassing_restricted) 115 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA 116 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 117 | # else 118 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 119 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 120 | # endif 121 | #endif 122 | 123 | #if !defined(SWIFT_PROTOCOL) 124 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 125 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 126 | #endif 127 | 128 | #if !defined(SWIFT_EXTENSION) 129 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) 130 | #endif 131 | 132 | #if !defined(OBJC_DESIGNATED_INITIALIZER) 133 | # if __has_attribute(objc_designated_initializer) 134 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 135 | # else 136 | # define OBJC_DESIGNATED_INITIALIZER 137 | # endif 138 | #endif 139 | #if !defined(SWIFT_ENUM_ATTR) 140 | # if defined(__has_attribute) && __has_attribute(enum_extensibility) 141 | # define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open))) 142 | # else 143 | # define SWIFT_ENUM_ATTR 144 | # endif 145 | #endif 146 | #if !defined(SWIFT_ENUM) 147 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type 148 | # if __has_feature(generalized_swift_name) 149 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type 150 | # else 151 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) 152 | # endif 153 | #endif 154 | #if !defined(SWIFT_UNAVAILABLE) 155 | # define SWIFT_UNAVAILABLE __attribute__((unavailable)) 156 | #endif 157 | #if !defined(SWIFT_UNAVAILABLE_MSG) 158 | # define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) 159 | #endif 160 | #if !defined(SWIFT_AVAILABILITY) 161 | # define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) 162 | #endif 163 | #if !defined(SWIFT_DEPRECATED) 164 | # define SWIFT_DEPRECATED __attribute__((deprecated)) 165 | #endif 166 | #if !defined(SWIFT_DEPRECATED_MSG) 167 | # define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) 168 | #endif 169 | #if __has_feature(attribute_diagnose_if_objc) 170 | # define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) 171 | #else 172 | # define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) 173 | #endif 174 | #if __has_feature(modules) 175 | #endif 176 | 177 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" 178 | #pragma clang diagnostic ignored "-Wduplicate-method-arg" 179 | #if __has_warning("-Wpragma-clang-attribute") 180 | # pragma clang diagnostic ignored "-Wpragma-clang-attribute" 181 | #endif 182 | #pragma clang diagnostic ignored "-Wunknown-pragmas" 183 | #pragma clang diagnostic ignored "-Wnullability" 184 | 185 | SWIFT_MODULE_NAMESPACE_PUSH("ETObserver") 186 | SWIFT_MODULE_NAMESPACE_POP 187 | #pragma clang diagnostic pop 188 | -------------------------------------------------------------------------------- /docs/docsets/ETLiveData.docset/Contents/Resources/Documents/Functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Functions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ETLiveData Docs (86% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 72 |
73 |
74 |
75 |

Functions

76 |

The following functions are available globally.

77 | 78 |
79 |
80 |
81 |
    82 |
  • 83 |
    84 | 85 | 86 | 87 | fatalError(_:file:line:) 88 | 89 |
    90 |
    91 |
    92 |
    93 |
    94 |
    95 |

    Undocumented

    96 | 97 |
    98 |
    99 |

    Declaration

    100 |
    101 |

    Swift

    102 |
    public func fatalError(_ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) -> Never
    103 | 104 |
    105 |
    106 |
    107 |
    108 |
  • 109 |
  • 110 |
    111 | 112 | 113 | 114 | unreachable() 115 | 116 |
    117 |
    118 |
    119 |
    120 |
    121 |
    122 |

    This is a noreturn function that pauses forever

    123 | 124 |
    125 |
    126 |

    Declaration

    127 |
    128 |

    Swift

    129 |
    public func unreachable() -> Never
    130 | 131 |
    132 |
    133 |
    134 |
    135 |
  • 136 |
137 |
138 |
139 |
140 | 144 |
145 |
146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /docs/Functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Functions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Functions

94 |

The following functions are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | onDealloc(of:closure:) 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Executes action upon deallocation of owner

    114 | 115 |
    116 |
    117 |

    Declaration

    118 |
    119 |

    Swift

    120 |
    public func onDealloc(of owner: Any, closure: @escaping () -> Void)
    121 | 122 |
    123 |
    124 |
    125 |

    Parameters

    126 | 127 | 128 | 129 | 134 | 139 | 140 | 141 | 146 | 151 | 152 | 153 |
    130 | 131 | owner 132 | 133 | 135 |
    136 |

    Owner to track.

    137 |
    138 |
    142 | 143 | closure 144 | 145 | 147 |
    148 |

    Closure to execute.

    149 |
    150 |
    154 |
    155 |
    156 |
    157 |
  • 158 |
159 |
160 |
161 |
162 | 166 |
167 |
168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Functions Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Functions

94 |

The following functions are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | onDealloc(of:closure:) 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Executes action upon deallocation of owner

    114 | 115 |
    116 |
    117 |

    Declaration

    118 |
    119 |

    Swift

    120 |
    public func onDealloc(of owner: Any, closure: @escaping () -> Void)
    121 | 122 |
    123 |
    124 |
    125 |

    Parameters

    126 | 127 | 128 | 129 | 134 | 139 | 140 | 141 | 146 | 151 | 152 | 153 |
    130 | 131 | owner 132 | 133 | 135 |
    136 |

    Owner to track.

    137 |
    138 |
    142 | 143 | closure 144 | 145 | 147 |
    148 |

    Closure to execute.

    149 |
    150 |
    154 |
    155 |
    156 |
    157 |
  • 158 |
159 |
160 |
161 |
162 | 166 |
167 |
168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /docs/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enumerations Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Enumerations

94 |

The following enumerations are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | StateValue 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Value with state added

    114 | 115 | See more 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    public enum StateValue<Value>
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
    132 |
  • 133 |
    134 | 135 | 136 | 137 | LifecycleState 138 | 139 |
    140 |
    141 |
    142 |
    143 |
    144 |
    145 |

    Valid states of LifecycleOwner

    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public enum LifecycleState
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 168 |
169 |
170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /docs/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Protocols

94 |

The following protocols are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | Observable 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Declares methods for observation.

    114 | 115 | See more 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    public protocol Observable : AnyObject
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
    132 |
  • 133 |
    134 | 135 | 136 | 137 | SingleEventObservable 138 | 139 |
    140 |
    141 |
    142 |
    143 |
    144 |
    145 |

    Declares methods for observation.

    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public protocol SingleEventObservable : AnyObject
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 168 |
169 |
170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /docs/Structs/FatalErrorUtil.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FatalErrorUtil Structure Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETLiveData Docs (86% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 73 |
74 |
75 |
76 |

FatalErrorUtil

77 |
78 |
79 |
public struct FatalErrorUtil
80 | 81 |
82 |
83 |

Utility functions that can replace and restore the fatalError global function.

84 | 85 |
86 |
87 |
88 |
    89 |
  • 90 |
    91 | 92 | 93 | 94 | replaceFatalError(closure:) 95 | 96 |
    97 |
    98 |
    99 |
    100 |
    101 |
    102 |

    Replace the fatalError global function with something else.

    103 | 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public static func replaceFatalError(closure: @escaping (String, StaticString, UInt) -> Never)
    110 | 111 |
    112 |
    113 |
    114 |
    115 |
  • 116 |
  • 117 |
    118 | 119 | 120 | 121 | restoreFatalError() 122 | 123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |

    Restore the fatalError global function back to the original Swift implementation

    130 | 131 |
    132 |
    133 |

    Declaration

    134 |
    135 |

    Swift

    136 |
    public static func restoreFatalError()
    137 | 138 |
    139 |
    140 |
    141 |
    142 |
  • 143 |
144 |
145 |
146 |
147 | 151 |
152 |
153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Enums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Enumerations Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Enumerations

94 |

The following enumerations are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | StateValue 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Value with state added

    114 | 115 | See more 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    public enum StateValue<Value>
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
    132 |
  • 133 |
    134 | 135 | 136 | 137 | LifecycleState 138 | 139 |
    140 |
    141 |
    142 |
    143 |
    144 |
    145 |

    Valid states of LifecycleOwner

    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public enum LifecycleState
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 168 |
169 |
170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Protocols.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Protocols Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETBinding Docs (89% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 90 |
91 |
92 |
93 |

Protocols

94 |

The following protocols are available globally.

95 | 96 |
97 |
98 |
99 |
    100 |
  • 101 |
    102 | 103 | 104 | 105 | Observable 106 | 107 |
    108 |
    109 |
    110 |
    111 |
    112 |
    113 |

    Declares methods for observation.

    114 | 115 | See more 116 |
    117 |
    118 |

    Declaration

    119 |
    120 |

    Swift

    121 |
    public protocol Observable : AnyObject
    122 | 123 |
    124 |
    125 |
    126 |
    127 |
  • 128 |
129 |
130 |
131 |
    132 |
  • 133 |
    134 | 135 | 136 | 137 | SingleEventObservable 138 | 139 |
    140 |
    141 |
    142 |
    143 |
    144 |
    145 |

    Declares methods for observation.

    146 | 147 | See more 148 |
    149 |
    150 |

    Declaration

    151 |
    152 |

    Swift

    153 |
    public protocol SingleEventObservable : AnyObject
    154 | 155 |
    156 |
    157 |
    158 |
    159 |
  • 160 |
161 |
162 |
163 |
164 | 168 |
169 |
170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /docs/docsets/ETBinding.docset/Contents/Resources/Documents/Structs/FatalErrorUtil.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FatalErrorUtil Structure Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ETLiveData Docs (86% documented)

18 |
19 |
20 |
21 | 26 |
27 |
28 | 73 |
74 |
75 |
76 |

FatalErrorUtil

77 |
78 |
79 |
public struct FatalErrorUtil
80 | 81 |
82 |
83 |

Utility functions that can replace and restore the fatalError global function.

84 | 85 |
86 |
87 |
88 |
    89 |
  • 90 |
    91 | 92 | 93 | 94 | replaceFatalError(closure:) 95 | 96 |
    97 |
    98 |
    99 |
    100 |
    101 |
    102 |

    Replace the fatalError global function with something else.

    103 | 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public static func replaceFatalError(closure: @escaping (String, StaticString, UInt) -> Never)
    110 | 111 |
    112 |
    113 |
    114 |
    115 |
  • 116 |
  • 117 |
    118 | 119 | 120 | 121 | restoreFatalError() 122 | 123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |

    Restore the fatalError global function back to the original Swift implementation

    130 | 131 |
    132 |
    133 |

    Declaration

    134 |
    135 |

    Swift

    136 |
    public static func restoreFatalError()
    137 | 138 |
    139 |
    140 |
    141 |
    142 |
  • 143 |
144 |
145 |
146 |
147 | 151 |
152 |
153 | 154 | 155 | 156 | --------------------------------------------------------------------------------