├── .gitignore ├── .idea ├── RGListKit.iml ├── modules.xml ├── vcs.xml ├── workspace.xml └── xcode.xml ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── Local Podspecs │ └── ProtoKit.podspec.json ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── ProtoKit │ ├── LICENSE │ ├── README.md │ └── Source │ │ ├── Describable+UIKit.swift │ │ ├── Describable.swift │ │ ├── ListableView │ │ ├── ListableView.swift │ │ ├── ListableViewDatasource.swift │ │ ├── ListableViewDelegate.swift │ │ ├── ListableViewLayout.swift │ │ └── UIKit │ │ │ ├── ListViewHolder+UICollectionViewDataSource.swift │ │ │ ├── ListViewHolder+UICollectionViewDelegateFlowLayout.swift │ │ │ ├── ListViewHolder+UITableViewDataSource.swift │ │ │ ├── ListViewHolder+UITableViewDelegate.swift │ │ │ ├── ListViewHolder.swift │ │ │ ├── ListableView+UICollectionView.swift │ │ │ └── ListableView+UITableView.swift │ │ ├── Nibable+UIKit.swift │ │ ├── Nibable.swift │ │ └── ReusableItem │ │ ├── ReusableListViewItem+UIKit.swift │ │ └── ReusableListViewItem.swift ├── ReactiveCocoa │ ├── LICENSE.md │ ├── README.md │ └── ReactiveCocoa │ │ ├── CocoaAction.swift │ │ ├── CocoaTarget.swift │ │ ├── DelegateProxy.swift │ │ ├── Deprecations+Removals.swift │ │ ├── DynamicProperty.swift │ │ ├── NSObject+Association.swift │ │ ├── NSObject+BindingTarget.swift │ │ ├── NSObject+Intercepting.swift │ │ ├── NSObject+KeyValueObserving.swift │ │ ├── NSObject+Lifetime.swift │ │ ├── NSObject+ObjCRuntime.swift │ │ ├── NSObject+ReactiveExtensionsProvider.swift │ │ ├── NSObject+Synchronizing.swift │ │ ├── ObjC+Constants.swift │ │ ├── ObjC+Messages.swift │ │ ├── ObjC+Runtime.swift │ │ ├── ObjC+RuntimeSubclassing.swift │ │ ├── ObjC+Selector.swift │ │ ├── ObjCRuntimeAliases.h │ │ ├── ObjCRuntimeAliases.m │ │ ├── ReactiveCocoa.h │ │ ├── ReactiveSwift+Lifetime.swift │ │ ├── Shared │ │ └── NSLayoutConstraint.swift │ │ ├── UIKit │ │ ├── ReusableComponents.swift │ │ ├── UIActivityIndicatorView.swift │ │ ├── UIBarButtonItem.swift │ │ ├── UIBarItem.swift │ │ ├── UIButton.swift │ │ ├── UICollectionView.swift │ │ ├── UIControl.swift │ │ ├── UIGestureRecognizer.swift │ │ ├── UIImageView.swift │ │ ├── UILabel.swift │ │ ├── UINavigationItem.swift │ │ ├── UIProgressView.swift │ │ ├── UIScrollView.swift │ │ ├── UISegmentedControl.swift │ │ ├── UITabBarItem.swift │ │ ├── UITableView.swift │ │ ├── UITextField.swift │ │ ├── UITextView.swift │ │ ├── UIView.swift │ │ └── iOS │ │ │ ├── UIDatePicker.swift │ │ │ ├── UIFeedbackGenerator.swift │ │ │ ├── UIImpact​Feedback​Generator.swift │ │ │ ├── UIKeyboard.swift │ │ │ ├── UINotification​Feedback​Generator.swift │ │ │ ├── UIPickerView.swift │ │ │ ├── UIRefreshControl.swift │ │ │ ├── UISearchBar.swift │ │ │ ├── UISelection​Feedback​Generator.swift │ │ │ ├── UISlider.swift │ │ │ ├── UIStepper.swift │ │ │ └── UISwitch.swift │ │ └── module.modulemap ├── ReactiveSwift │ ├── LICENSE.md │ ├── README.md │ └── Sources │ │ ├── Action.swift │ │ ├── Atomic.swift │ │ ├── Bag.swift │ │ ├── Deprecations+Removals.swift │ │ ├── Disposable.swift │ │ ├── Event.swift │ │ ├── EventLogger.swift │ │ ├── Flatten.swift │ │ ├── FoundationExtensions.swift │ │ ├── Lifetime.swift │ │ ├── Observer.swift │ │ ├── Optional.swift │ │ ├── Property.swift │ │ ├── Reactive.swift │ │ ├── ResultExtensions.swift │ │ ├── Scheduler.swift │ │ ├── Signal.swift │ │ ├── SignalProducer.swift │ │ ├── UnidirectionalBinding.swift │ │ ├── UninhabitedTypeGuards.swift │ │ └── ValidatingProperty.swift ├── Result │ ├── LICENSE │ ├── README.md │ └── Result │ │ ├── Result.swift │ │ └── ResultProtocol.swift └── Target Support Files │ ├── Pods-RGListKit │ ├── Info.plist │ ├── Pods-RGListKit-acknowledgements.markdown │ ├── Pods-RGListKit-acknowledgements.plist │ ├── Pods-RGListKit-dummy.m │ ├── Pods-RGListKit-frameworks.sh │ ├── Pods-RGListKit-resources.sh │ ├── Pods-RGListKit-umbrella.h │ ├── Pods-RGListKit.debug.xcconfig │ ├── Pods-RGListKit.modulemap │ └── Pods-RGListKit.release.xcconfig │ ├── ProtoKit │ ├── Info.plist │ ├── ProtoKit-dummy.m │ ├── ProtoKit-prefix.pch │ ├── ProtoKit-umbrella.h │ ├── ProtoKit.modulemap │ └── ProtoKit.xcconfig │ ├── ReactiveCocoa │ ├── Info.plist │ ├── ReactiveCocoa-dummy.m │ ├── ReactiveCocoa-prefix.pch │ ├── ReactiveCocoa.modulemap │ └── ReactiveCocoa.xcconfig │ ├── ReactiveSwift │ ├── Info.plist │ ├── ReactiveSwift-dummy.m │ ├── ReactiveSwift-prefix.pch │ ├── ReactiveSwift-umbrella.h │ ├── ReactiveSwift.modulemap │ └── ReactiveSwift.xcconfig │ └── Result │ ├── Info.plist │ ├── Result-dummy.m │ ├── Result-prefix.pch │ ├── Result-umbrella.h │ ├── Result.modulemap │ └── Result.xcconfig ├── README.md ├── RGListKit.podspec ├── RGListKit.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── RGListKit.xcworkspace └── contents.xcworkspacedata ├── RGListKit ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CollectionCell.swift ├── CollectionViewController.swift ├── Info.plist ├── StackItemView.swift ├── StackItemView.xib ├── StackViewController.swift ├── TableCell.swift └── TableViewController.swift └── Source ├── DiffKit ├── Dwifft+UIKit.swift ├── Dwifft.swift ├── RGCollectionViewDiffCalculator.swift ├── RGTableViewDiffCalculator.swift └── SectionedValues.swift ├── ListKit ├── Core │ ├── DiffableListViewHolder+Extension.swift │ ├── DiffableListViewHolder.swift │ ├── EquatableItemModel.swift │ ├── ListViewItemModel.swift │ ├── ListViewItemModelInjectable.swift │ ├── ListableDiffCalculator.swift │ └── SectionModel.swift └── Extension │ ├── Array+RGListKit.swift │ └── ListableViewDatasource+Extension.swift ├── Reactive └── Reactive.swift └── StackViewKit ├── StackViewCollectionViewCell.swift ├── StackViewCollectionViewCell.xib ├── StackViewHolder.swift ├── StackViewItemHolder.swift ├── StackViewItemModel.swift ├── StackViewItemProvider.swift └── UIView+Extension.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | 35 | ### macOS ### 36 | *.DS_Store 37 | .AppleDouble 38 | .LSOverride 39 | 40 | # Icon must end with two \r 41 | Icon 42 | 43 | # Thumbnails 44 | ._* 45 | 46 | # Files that might appear in the root of a volume 47 | .DocumentRevisions-V100 48 | .fseventsd 49 | .Spotlight-V100 50 | .TemporaryItems 51 | .Trashes 52 | .VolumeIcon.icns 53 | .com.apple.timemachine.donotpresent 54 | 55 | # Directories potentially created on remote AFP share 56 | .AppleDB 57 | .AppleDesktop 58 | Network Trash Folder 59 | Temporary Items 60 | .apdisk 61 | -------------------------------------------------------------------------------- /.idea/RGListKit.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/xcode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ritesh Gupta 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 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'RGListKit' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | pod 'ReactiveSwift', '~> 3.0' 8 | pod 'ReactiveCocoa', '~> 7.0' 9 | pod 'ProtoKit', :git => 'https://github.com/riteshhgupta/ProtoKit.git' 10 | end 11 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ProtoKit (1.2) 3 | - ReactiveCocoa (7.0.1): 4 | - ReactiveSwift (~> 3.0) 5 | - ReactiveSwift (3.0.0): 6 | - Result (~> 3.2) 7 | - Result (3.2.4) 8 | 9 | DEPENDENCIES: 10 | - ProtoKit (from `https://github.com/riteshhgupta/ProtoKit.git`) 11 | - ReactiveCocoa (~> 7.0) 12 | - ReactiveSwift (~> 3.0) 13 | 14 | EXTERNAL SOURCES: 15 | ProtoKit: 16 | :git: https://github.com/riteshhgupta/ProtoKit.git 17 | 18 | CHECKOUT OPTIONS: 19 | ProtoKit: 20 | :commit: d8572f3c0ff54ef551ee72fb8280746788bb4098 21 | :git: https://github.com/riteshhgupta/ProtoKit.git 22 | 23 | SPEC CHECKSUMS: 24 | ProtoKit: 9402368b3cd1ffa3a1f6f8ddde34313a5803b96e 25 | ReactiveCocoa: a1b5d502d0d1534f9a72981a485b297b17127f83 26 | ReactiveSwift: d9fe0db33c1aaabecb092e8de83cf52875c0de6f 27 | Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10 28 | 29 | PODFILE CHECKSUM: 44ea69dc75d7f7b64c60cd06c703e39e00411424 30 | 31 | COCOAPODS: 1.3.1 32 | -------------------------------------------------------------------------------- /Pods/Local Podspecs/ProtoKit.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ProtoKit", 3 | "version": "1.2", 4 | "summary": "ProtoKit - Protocol oriented UIKit", 5 | "authors": { 6 | "Ritesh Gupta": "rg.riteshh@gmail.com" 7 | }, 8 | "license": "MIT", 9 | "homepage": "https://github.com/riteshhgupta/ProtoKit", 10 | "source": { 11 | "git": "https://github.com/riteshhgupta/ProtoKit.git", 12 | "tag": "1.2" 13 | }, 14 | "platforms": { 15 | "ios": "9.0" 16 | }, 17 | "requires_arc": true, 18 | "source_files": "Source/**/*.swift" 19 | } 20 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ProtoKit (1.2) 3 | - ReactiveCocoa (7.0.1): 4 | - ReactiveSwift (~> 3.0) 5 | - ReactiveSwift (3.0.0): 6 | - Result (~> 3.2) 7 | - Result (3.2.4) 8 | 9 | DEPENDENCIES: 10 | - ProtoKit (from `https://github.com/riteshhgupta/ProtoKit.git`) 11 | - ReactiveCocoa (~> 7.0) 12 | - ReactiveSwift (~> 3.0) 13 | 14 | EXTERNAL SOURCES: 15 | ProtoKit: 16 | :git: https://github.com/riteshhgupta/ProtoKit.git 17 | 18 | CHECKOUT OPTIONS: 19 | ProtoKit: 20 | :commit: d8572f3c0ff54ef551ee72fb8280746788bb4098 21 | :git: https://github.com/riteshhgupta/ProtoKit.git 22 | 23 | SPEC CHECKSUMS: 24 | ProtoKit: 9402368b3cd1ffa3a1f6f8ddde34313a5803b96e 25 | ReactiveCocoa: a1b5d502d0d1534f9a72981a485b297b17127f83 26 | ReactiveSwift: d9fe0db33c1aaabecb092e8de83cf52875c0de6f 27 | Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10 28 | 29 | PODFILE CHECKSUM: 44ea69dc75d7f7b64c60cd06c703e39e00411424 30 | 31 | COCOAPODS: 1.3.1 32 | -------------------------------------------------------------------------------- /Pods/ProtoKit/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ritesh Gupta 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 | -------------------------------------------------------------------------------- /Pods/ProtoKit/README.md: -------------------------------------------------------------------------------- 1 | # ProtoKit 2 | 3 | ProtoKit is a protocol oriented UIKit! 4 | 5 | ## Installation 6 | 7 | ### Cocoapods 8 | To integrate ProtoKit into your Xcode project using CocoaPods, specify it in your Podfile: 9 | 10 | ``` 11 | pod 'ProtoKit', :git => 'https://github.com/riteshhgupta/ProtoKit.git' 12 | ``` 13 | 14 | ## Example 15 | // TODO 16 | 17 | ## Contributing 18 | 19 | Contributions are welcome and encouraged! Open an [issue](https://github.com/riteshhgupta/ProtoKit/issues/new) or submit a [pull request](https://github.com/riteshhgupta/ProtoKit/compare) 🚀 20 | 21 | ## Licence 22 | 23 | ProtoKit is available under the MIT license. See the LICENSE file for more info. 24 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/Describable+UIKit.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Describable+UIKit.swift 4 | // ProtocolUIKit 5 | // 6 | // Created by Ritesh Gupta on 05/12/17. 7 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 8 | // 9 | 10 | import Foundation 11 | import UIKit 12 | 13 | extension UIView: Describable {} 14 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/Describable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Describable.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol Describable { 12 | 13 | var typeName: String { get } 14 | static var typeName: String { get } 15 | } 16 | 17 | public extension Describable { 18 | 19 | var typeName: String { 20 | return String(describing: self) 21 | } 22 | 23 | static var typeName: String { 24 | return String(describing: self) 25 | } 26 | } 27 | 28 | public extension Describable where Self: NSObjectProtocol { 29 | 30 | var typeName: String { 31 | let _type = type(of: self) 32 | return String(describing: _type) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/ListableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableView.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public typealias ReusableView = ReusableListViewItem & UIView 13 | 14 | public protocol ListableView: class { 15 | 16 | var listDelegate: ListableViewDelegate? { get set } 17 | var listDatasource: ListableViewDatasource? { get set } 18 | 19 | func registerItem(with nib: UINib, for identifier: String) 20 | func registerHeaderFooterItem(with nib: UINib, for identifier: String, of kind: String) 21 | func reusableItem(withIdentifier identifier: String, for indexPath: IndexPath) -> Item 22 | func reusableHeaderFooterItem(withIdentifier identifier: String, for indexPath: IndexPath, of kind: String) -> Item? 23 | func reloadItems() 24 | } 25 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/ListableViewDatasource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableViewDatasource.swift 3 | // ListableView 4 | // 5 | // Created by Ritesh Gupta on 05/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol ListableViewDatasource: NSObjectProtocol { 13 | 14 | func numberOfSectionsIn(listableView: ListableView) -> Int 15 | func listableView(_ listableView: ListableView, numberOfItemsInSection section: Int) -> Int 16 | func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item 17 | func listableView(_ listableView: ListableView, viewForHeaderFooterAt indexPath: IndexPath, of kind: String) -> Item? 18 | } 19 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/ListableViewDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableViewDelegate.swift 3 | // ListableView 4 | // 5 | // Created by Ritesh Gupta on 05/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol ListableViewDelegate: NSObjectProtocol {} 12 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/ListableViewLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableViewLayout.swift 3 | // ListableView 4 | // 5 | // Created by Ritesh Gupta on 05/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol ListableViewLayout: NSObjectProtocol { 13 | 14 | func listableView(_ listableView: ListableView, estimatedHeightForItemAt indexPath: IndexPath) -> CGFloat 15 | func listableView(_ listableView: ListableView, sizeForItemAt indexPath: IndexPath) -> CGSize 16 | func listableView(_ listableView: ListableView, heightForHeaderInSection section: Int) -> CGFloat 17 | func listableView(_ listableView: ListableView, heightForFooterInSection section: Int) -> CGFloat 18 | func listableView(_ listableView: ListableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat 19 | func listableView(_ listableView: ListableView, estimatedHeightForFooterInSection section: Int) -> CGFloat 20 | } 21 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListViewHolder+UICollectionViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewHolder+UICollectionViewDataSource.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 06/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `ListViewHolder` conforms to `UICollectionViewDataSource` to provide 14 | data-source support for `UICollectionView` 15 | */ 16 | 17 | extension ListViewHolder: UICollectionViewDataSource { 18 | 19 | open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 20 | return listableView(collectionView, itemForItemAt: indexPath) 21 | } 22 | 23 | open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 24 | return listableView(collectionView, numberOfItemsInSection: section) 25 | } 26 | 27 | open func numberOfSections(in collectionView: UICollectionView) -> Int { 28 | return numberOfSectionsIn(listableView: collectionView) 29 | } 30 | 31 | open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { 32 | let view: UICollectionReusableView? = listableView(collectionView, viewForHeaderFooterAt: indexPath, of: kind) 33 | return view! 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListViewHolder+UICollectionViewDelegateFlowLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewHolder+UICollectionViewDelegateFlowLayout.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 06/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `ListViewHolder` conforms to `UICollectionViewDelegateFlowLayout` to provide 14 | delegate support for `UICollectionView` 15 | */ 16 | 17 | extension ListViewHolder: UICollectionViewDelegateFlowLayout { 18 | 19 | open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 20 | return listableView(collectionView, sizeForItemAt: indexPath) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListViewHolder+UITableViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewHolder+UITableViewDataSource.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 06/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `ListViewHolder` conforms to `UITableViewDataSource` to provide data-source 14 | support for `UITableView` 15 | */ 16 | 17 | extension ListViewHolder: UITableViewDataSource { 18 | 19 | open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 20 | return listableView(tableView, itemForItemAt: indexPath) 21 | } 22 | 23 | open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 24 | return listableView(tableView, numberOfItemsInSection: section) 25 | } 26 | 27 | open func numberOfSections(in tableView: UITableView) -> Int { 28 | return numberOfSectionsIn(listableView: tableView) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListViewHolder+UITableViewDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewHolder+UITableViewDelegate.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 06/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `ListViewHolder` conforms to `UITableViewDelegate` to provide delegate 14 | support for `UITableView` 15 | */ 16 | 17 | extension ListViewHolder: UITableViewDelegate { 18 | 19 | open func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 20 | let indexPath = IndexPath(row: 0, section: section) 21 | let view: UITableViewHeaderFooterView? = listableView(tableView, viewForHeaderFooterAt: indexPath, of: UICollectionElementKindSectionHeader) 22 | return view 23 | } 24 | 25 | open func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { 26 | let indexPath = IndexPath(row: 0, section: section) 27 | let view: UITableViewHeaderFooterView? = listableView(tableView, viewForHeaderFooterAt: indexPath, of: UICollectionElementKindSectionHeader) 28 | return view 29 | } 30 | 31 | open func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 32 | return listableView(tableView, sizeForItemAt: indexPath).height 33 | } 34 | 35 | open func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { 36 | return listableView(tableView, estimatedHeightForItemAt: indexPath) 37 | } 38 | 39 | open func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 40 | return listableView(tableView, heightForHeaderInSection: section) 41 | } 42 | 43 | open func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { 44 | return listableView(tableView, heightForFooterInSection: section) 45 | } 46 | 47 | open func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { 48 | return listableView(tableView, estimatedHeightForHeaderInSection: section) 49 | } 50 | 51 | open func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { 52 | return listableView(tableView, estimatedHeightForFooterInSection: section) 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListViewHolder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewHolder.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 07/12/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class ListViewHolder: NSObject { 13 | 14 | public let listView: ListableView 15 | 16 | public init(listView: ListableView) { 17 | self.listView = listView 18 | super.init() 19 | self.listView.listDelegate = self 20 | self.listView.listDatasource = self 21 | } 22 | 23 | open func numberOfSectionsIn(listableView: ListableView) -> Int { 24 | // override 25 | return 0 26 | } 27 | 28 | open func listableView(_ listableView: ListableView, numberOfItemsInSection section: Int) -> Int { 29 | // override 30 | return 0 31 | } 32 | 33 | open func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item { 34 | // override 35 | return listView.reusableItem(withIdentifier: "", for: indexPath) 36 | } 37 | 38 | open func listableView(_ listableView: ListableView, viewForHeaderFooterAt indexPath: IndexPath, of kind: String) -> Item? { 39 | // override 40 | return listView.reusableHeaderFooterItem(withIdentifier: "", for: indexPath, of: kind) 41 | } 42 | 43 | open func listableView(_ listableView: ListableView, sizeForItemAt indexPath: IndexPath) -> CGSize { 44 | // override 45 | return .zero 46 | } 47 | 48 | open func listableView(_ listableView: ListableView, estimatedHeightForItemAt indexPath: IndexPath) -> CGFloat { 49 | // override 50 | return 0.0 51 | } 52 | 53 | open func listableView(_ listableView: ListableView, heightForHeaderInSection section: Int) -> CGFloat { 54 | // override 55 | return 0.0 56 | } 57 | 58 | open func listableView(_ listableView: ListableView, heightForFooterInSection section: Int) -> CGFloat { 59 | // override 60 | return 0.0 61 | } 62 | 63 | open func listableView(_ listableView: ListableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { 64 | // override 65 | return 0.0 66 | } 67 | 68 | open func listableView(_ listableView: ListableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { 69 | // override 70 | return 0.0 71 | } 72 | } 73 | 74 | extension ListViewHolder: ListableViewDelegate {} 75 | 76 | extension ListViewHolder: ListableViewDatasource {} 77 | 78 | extension ListViewHolder: ListableViewLayout {} 79 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListableView+UICollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableView+UICollectionView.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 07/12/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UICollectionView: ListableView { 13 | 14 | public var listDelegate: ListableViewDelegate? { 15 | get { return delegate as? ListableViewDelegate } 16 | set { delegate = newValue as? UICollectionViewDelegateFlowLayout } 17 | } 18 | 19 | public var listDatasource: ListableViewDatasource? { 20 | get { return dataSource as? ListableViewDatasource } 21 | set { dataSource = newValue as? UICollectionViewDataSource } 22 | } 23 | 24 | public func registerItem(with nib: UINib, for identifier: String) { 25 | register(nib, forCellWithReuseIdentifier: identifier) 26 | } 27 | 28 | public func registerHeaderFooterItem(with nib: UINib, for identifier: String, of kind: String) { 29 | register(nib, forSupplementaryViewOfKind: kind, withReuseIdentifier: identifier) 30 | } 31 | 32 | public func reusableItem(withIdentifier identifier: String, for indexPath: IndexPath) -> Item { 33 | return dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! Item 34 | } 35 | 36 | public func reusableHeaderFooterItem(withIdentifier identifier: String, for indexPath: IndexPath, of kind: String) -> Item? { 37 | return dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier, for: indexPath) as? Item 38 | } 39 | 40 | public func reloadItems() { 41 | reloadData() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ListableView/UIKit/ListableView+UITableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableView+UIKit.swift 3 | // ListableView 4 | // 5 | // Created by Ritesh Gupta on 05/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UITableView: ListableView { 13 | 14 | public var listDelegate: ListableViewDelegate? { 15 | get { return delegate as? ListableViewDelegate } 16 | set { delegate = newValue as? UITableViewDelegate } 17 | } 18 | 19 | public var listDatasource: ListableViewDatasource? { 20 | get { return dataSource as? ListableViewDatasource } 21 | set { dataSource = newValue as? UITableViewDataSource } 22 | } 23 | 24 | public func registerItem(with nib: UINib, for identifier: String) { 25 | register(nib, forCellReuseIdentifier: identifier) 26 | } 27 | 28 | public func registerHeaderFooterItem(with nib: UINib, for identifier: String, of kind: String) { 29 | register(nib, forHeaderFooterViewReuseIdentifier: identifier) 30 | } 31 | 32 | public func reusableItem(withIdentifier identifier: String, for indexPath: IndexPath) -> Item { 33 | return dequeueReusableCell(withIdentifier: identifier, for: indexPath) as! Item 34 | } 35 | 36 | public func reusableHeaderFooterItem(withIdentifier identifier: String, for indexPath: IndexPath, of kind: String) -> Item? { 37 | return dequeueReusableHeaderFooterView(withIdentifier: identifier) as? Item 38 | } 39 | 40 | public func reloadItems() { 41 | reloadData() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/Nibable+UIKit.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Nibable+UIKit.swift 4 | // ProtocolUIKit 5 | // 6 | // Created by Ritesh Gupta on 05/12/17. 7 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 8 | // 9 | 10 | import Foundation 11 | import UIKit 12 | 13 | extension UIView: Nibable {} 14 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/Nibable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nibable.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol Nibable: class { 13 | 14 | var nib: UINib { get } 15 | static var nib: UINib { get } 16 | static func instance() -> UIView 17 | } 18 | 19 | public extension Nibable where Self: Describable { 20 | 21 | static var nib: UINib { 22 | return UINib(nibName: typeName, bundle: nil) 23 | } 24 | 25 | var nib: UINib { 26 | return UINib(nibName: typeName, bundle: nil) 27 | } 28 | 29 | static func instance() -> UIView { 30 | return nib.instantiate(withOwner: self, options: nil).first as! UIView 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ReusableItem/ReusableListViewItem+UIKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReusableListViewItem+UIKit.swift 3 | // ListableView 4 | // 5 | // Created by Ritesh Gupta on 05/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UITableViewCell: ReusableListViewItem {} 13 | 14 | extension UITableViewHeaderFooterView: ReusableListViewItem {} 15 | 16 | extension UICollectionReusableView: ReusableListViewItem {} 17 | 18 | -------------------------------------------------------------------------------- /Pods/ProtoKit/Source/ReusableItem/ReusableListViewItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReusableListViewItem.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol ReusableListViewItem: Nibable, Describable {} 13 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/LICENSE.md: -------------------------------------------------------------------------------- 1 | **Copyright (c) 2012 - 2016, GitHub, Inc.** 2 | **All rights reserved.** 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/CocoaAction.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | /// CocoaAction wraps an `Action` for use by a UI control (such as `NSControl` or 6 | /// `UIControl`). 7 | public final class CocoaAction: NSObject { 8 | /// The selector for message senders. 9 | public static var selector: Selector { 10 | return #selector(CocoaAction.execute(_:)) 11 | } 12 | 13 | /// Whether the action is enabled. 14 | /// 15 | /// This property will only change on the main thread. 16 | public let isEnabled: Property 17 | 18 | /// Whether the action is executing. 19 | /// 20 | /// This property will only change on the main thread. 21 | public let isExecuting: Property 22 | 23 | private let _execute: (Sender) -> Void 24 | 25 | /// Initialize a CocoaAction that invokes the given Action by mapping the 26 | /// sender to the input type of the Action. 27 | /// 28 | /// - parameters: 29 | /// - action: The Action. 30 | /// - inputTransform: A closure that maps Sender to the input type of the 31 | /// Action. 32 | public init(_ action: Action, _ inputTransform: @escaping (Sender) -> Input) { 33 | _execute = { sender in 34 | let producer = action.apply(inputTransform(sender)) 35 | producer.start() 36 | } 37 | 38 | isEnabled = Property(initial: action.isEnabled.value, 39 | then: action.isEnabled.producer.observe(on: UIScheduler())) 40 | isExecuting = Property(initial: action.isExecuting.value, 41 | then: action.isExecuting.producer.observe(on: UIScheduler())) 42 | 43 | super.init() 44 | } 45 | 46 | /// Initialize a CocoaAction that invokes the given Action. 47 | /// 48 | /// - parameters: 49 | /// - action: The Action. 50 | public convenience init(_ action: Action<(), Output, Error>) { 51 | self.init(action, { _ in }) 52 | } 53 | 54 | /// Initialize a CocoaAction that invokes the given Action with the given 55 | /// constant. 56 | /// 57 | /// - parameters: 58 | /// - action: The Action. 59 | /// - input: The constant value as the input to the action. 60 | public convenience init(_ action: Action, input: Input) { 61 | self.init(action, { _ in input }) 62 | } 63 | 64 | /// Attempt to execute the underlying action with the given input, subject 65 | /// to the behavior described by the initializer that was used. 66 | /// 67 | /// - parameters: 68 | /// - sender: The sender which initiates the attempt. 69 | @IBAction public func execute(_ sender: Any) { 70 | _execute(sender as! Sender) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/CocoaTarget.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | /// A target that accepts action messages. 6 | internal final class CocoaTarget: NSObject { 7 | private enum State { 8 | case idle 9 | case sending(queue: [Value]) 10 | } 11 | 12 | private let observer: Signal.Observer 13 | private let transform: (Any?) -> Value 14 | 15 | private var state: State 16 | 17 | internal init(_ observer: Signal.Observer, transform: @escaping (Any?) -> Value) { 18 | self.observer = observer 19 | self.transform = transform 20 | self.state = .idle 21 | } 22 | 23 | /// Broadcast the action message to all observers. 24 | /// 25 | /// Reentrancy is supported, and the action message would be deferred until the 26 | /// delivery of the current message has completed. 27 | /// 28 | /// - note: It should only be invoked on the main queue. 29 | /// 30 | /// - parameters: 31 | /// - sender: The object which sends the action message. 32 | @objc internal func invoke(_ sender: Any?) { 33 | switch state { 34 | case .idle: 35 | state = .sending(queue: []) 36 | observer.send(value: transform(sender)) 37 | 38 | while case let .sending(values) = state { 39 | guard !values.isEmpty else { 40 | break 41 | } 42 | 43 | state = .sending(queue: Array(values.dropFirst())) 44 | observer.send(value: values[0]) 45 | } 46 | 47 | state = .idle 48 | 49 | case let .sending(values): 50 | state = .sending(queue: values + [transform(sender)]) 51 | } 52 | } 53 | } 54 | 55 | extension CocoaTarget where Value == Void { 56 | internal convenience init(_ observer: Signal<(), NoError>.Observer) { 57 | self.init(observer, transform: { _ in }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/DelegateProxy.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | 4 | internal class DelegateProxy: NSObject { 5 | internal weak var forwardee: Delegate? { 6 | didSet { 7 | originalSetter(self) 8 | } 9 | } 10 | 11 | internal var interceptedSelectors: Set = [] 12 | 13 | private let lifetime: Lifetime 14 | private let originalSetter: (AnyObject) -> Void 15 | 16 | required init(lifetime: Lifetime, _ originalSetter: @escaping (AnyObject) -> Void) { 17 | self.lifetime = lifetime 18 | self.originalSetter = originalSetter 19 | } 20 | 21 | override func forwardingTarget(for selector: Selector!) -> Any? { 22 | return interceptedSelectors.contains(selector) ? nil : forwardee 23 | } 24 | 25 | func intercept(_ selector: Selector) -> Signal<(), NoError> { 26 | interceptedSelectors.insert(selector) 27 | originalSetter(self) 28 | return self.reactive.trigger(for: selector).take(during: lifetime) 29 | } 30 | 31 | func intercept(_ selector: Selector) -> Signal<[Any?], NoError> { 32 | interceptedSelectors.insert(selector) 33 | originalSetter(self) 34 | return self.reactive.signal(for: selector).take(during: lifetime) 35 | } 36 | 37 | override func responds(to selector: Selector!) -> Bool { 38 | if interceptedSelectors.contains(selector) { 39 | return true 40 | } 41 | 42 | return (forwardee?.responds(to: selector) ?? false) || super.responds(to: selector) 43 | } 44 | } 45 | 46 | private let hasSwizzledKey = AssociationKey(default: false) 47 | 48 | extension DelegateProxy { 49 | // FIXME: This is a workaround to a compiler issue, where any use of `Self` 50 | // through a protocol would result in the following error messages: 51 | // 1. PHI node operands are not the same type as the result! 52 | // 2. LLVM ERROR: Broken function found, compilation aborted! 53 | internal static func proxy>( 54 | for instance: NSObject, 55 | setter: Selector, 56 | getter: Selector 57 | ) -> P { 58 | return _proxy(for: instance, setter: setter, getter: getter) as! P 59 | } 60 | 61 | private static func _proxy( 62 | for instance: NSObject, 63 | setter: Selector, 64 | getter: Selector 65 | ) -> AnyObject { 66 | return instance.synchronized { 67 | let key = AssociationKey(setter.delegateProxyAlias) 68 | 69 | if let proxy = instance.associations.value(forKey: key) { 70 | return proxy 71 | } 72 | 73 | let superclass: AnyClass = class_getSuperclass(swizzleClass(instance))! 74 | 75 | let invokeSuperSetter: @convention(c) (NSObject, AnyClass, Selector, AnyObject?) -> Void = { object, superclass, selector, delegate in 76 | typealias Setter = @convention(c) (NSObject, Selector, AnyObject?) -> Void 77 | let impl = class_getMethodImplementation(superclass, selector) 78 | unsafeBitCast(impl, to: Setter.self)(object, selector, delegate) 79 | } 80 | 81 | let newSetterImpl: @convention(block) (NSObject, AnyObject?) -> Void = { object, delegate in 82 | if let proxy = object.associations.value(forKey: key) as! DelegateProxy? { 83 | proxy.forwardee = (delegate as! Delegate?) 84 | } else { 85 | invokeSuperSetter(object, superclass, setter, delegate) 86 | } 87 | } 88 | 89 | // Hide the original setter, and redirect subsequent delegate assignment 90 | // to the proxy. 91 | instance.swizzle((setter, newSetterImpl), key: hasSwizzledKey) 92 | 93 | // As Objective-C classes may cache the information of their delegate at 94 | // the time the delegates are set, the information has to be "flushed" 95 | // whenever the proxy forwardee is replaced or a selector is intercepted. 96 | let proxy = self.init(lifetime: instance.reactive.lifetime) { [weak instance] proxy in 97 | guard let instance = instance else { return } 98 | invokeSuperSetter(instance, superclass, setter, proxy) 99 | } 100 | 101 | typealias Getter = @convention(c) (NSObject, Selector) -> AnyObject? 102 | let getterImpl: IMP = class_getMethodImplementation(object_getClass(instance), getter)! 103 | let original = unsafeBitCast(getterImpl, to: Getter.self)(instance, getter) as! Delegate? 104 | 105 | // `proxy.forwardee` would invoke the original setter regardless of 106 | // `original` being `nil` or not. 107 | proxy.forwardee = original 108 | 109 | // The proxy must be associated after it is set as the target, since 110 | // `base` may be an isa-swizzled instance that is using the injected 111 | // setters above. 112 | instance.associations.setValue(proxy, forKey: key) 113 | 114 | return proxy 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/Deprecations+Removals.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | 4 | extension Action { 5 | @available(*, unavailable, message:"Use the `CocoaAction` initializers instead.") 6 | public var unsafeCocoaAction: CocoaAction { fatalError() } 7 | } 8 | 9 | extension Reactive where Base: NSObject { 10 | @available(*, deprecated, renamed: "producer(forKeyPath:)") 11 | public func values(forKeyPath keyPath: String) -> SignalProducer { 12 | return producer(forKeyPath: keyPath) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/DynamicProperty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | /// A typed mutable property view to a certain key path of an Objective-C object using 6 | /// Key-Value Coding and Key-Value Observing. 7 | /// 8 | /// Bindings towards a `DynamicProperty` would be directed to the underlying Objective-C 9 | /// object, and would not be affected by the deinitialization of the `DynamicProperty`. 10 | public final class DynamicProperty: MutablePropertyProtocol { 11 | private weak var object: NSObject? 12 | private let keyPath: String 13 | private let cache: Property 14 | private let transform: (Value) -> Any? 15 | 16 | /// The current value of the property, as read and written using Key-Value 17 | /// Coding. 18 | public var value: Value { 19 | get { return cache.value } 20 | set { object?.setValue(transform(newValue), forKeyPath: keyPath) } 21 | } 22 | 23 | /// The lifetime of the property. 24 | public var lifetime: Lifetime { 25 | return object?.reactive.lifetime ?? .empty 26 | } 27 | 28 | /// The binding target of the property. 29 | public var bindingTarget: BindingTarget { 30 | return BindingTarget(lifetime: lifetime) { [weak object, keyPath] value in 31 | object?.setValue(value, forKey: keyPath) 32 | } 33 | } 34 | 35 | /// A producer that will create a Key-Value Observer for the given object, 36 | /// send its initial value then all changes over time, and then complete 37 | /// when the observed object has deallocated. 38 | /// 39 | /// - important: This only works if the object given to init() is KVO-compliant. 40 | /// Most UI controls are not! 41 | public var producer: SignalProducer { 42 | return cache.producer 43 | } 44 | 45 | public var signal: Signal { 46 | return cache.signal 47 | } 48 | 49 | internal init(object: NSObject, keyPath: String, cache: Property, transform: @escaping (Value) -> Any?) { 50 | self.object = object 51 | self.keyPath = keyPath 52 | self.cache = cache 53 | self.transform = transform 54 | } 55 | 56 | /// Create a typed mutable view to the given key path of the given Objective-C object. 57 | /// The generic type `Value` can be any Swift type, and will be bridged to Objective-C 58 | /// via `Any`. 59 | /// 60 | /// - parameters: 61 | /// - object: The Objective-C object to be observed. 62 | /// - keyPath: The key path to observe. 63 | public convenience init(object: NSObject, keyPath: String) { 64 | self.init(object: object, keyPath: keyPath, cache: Property(object: object, keyPath: keyPath), transform: { $0 }) 65 | } 66 | } 67 | 68 | extension DynamicProperty where Value: OptionalProtocol { 69 | /// Create a typed mutable view to the given key path of the given Objective-C object. 70 | /// The generic type `Value` can be any Swift type, and will be bridged to Objective-C 71 | /// via `Any`. 72 | /// 73 | /// - parameters: 74 | /// - object: The Objective-C object to be observed. 75 | /// - keyPath: The key path to observe. 76 | public convenience init(object: NSObject, keyPath: String) { 77 | self.init(object: object, keyPath: keyPath, cache: Property(object: object, keyPath: keyPath), transform: { $0.optional }) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+Association.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | 3 | internal struct AssociationKey { 4 | fileprivate let address: UnsafeRawPointer 5 | fileprivate let `default`: Value! 6 | 7 | /// Create an ObjC association key. 8 | /// 9 | /// - warning: The key must be uniqued. 10 | /// 11 | /// - parameters: 12 | /// - default: The default value, or `nil` to trap on undefined value. It is 13 | /// ignored if `Value` is an optional. 14 | init(default: Value? = nil) { 15 | self.address = UnsafeRawPointer(UnsafeMutablePointer.allocate(capacity: 1)) 16 | self.default = `default` 17 | } 18 | 19 | /// Create an ObjC association key from a `StaticString`. 20 | /// 21 | /// - precondition: `key` has a pointer representation. 22 | /// 23 | /// - parameters: 24 | /// - default: The default value, or `nil` to trap on undefined value. It is 25 | /// ignored if `Value` is an optional. 26 | init(_ key: StaticString, default: Value? = nil) { 27 | assert(key.hasPointerRepresentation) 28 | self.address = UnsafeRawPointer(key.utf8Start) 29 | self.default = `default` 30 | } 31 | 32 | /// Create an ObjC association key from a `Selector`. 33 | /// 34 | /// - parameters: 35 | /// - default: The default value, or `nil` to trap on undefined value. It is 36 | /// ignored if `Value` is an optional. 37 | init(_ key: Selector, default: Value? = nil) { 38 | self.address = UnsafeRawPointer(key.utf8Start) 39 | self.default = `default` 40 | } 41 | } 42 | 43 | internal struct Associations { 44 | fileprivate let base: Base 45 | 46 | init(_ base: Base) { 47 | self.base = base 48 | } 49 | } 50 | 51 | extension Reactive where Base: NSObjectProtocol { 52 | /// Retrieve the associated value for the specified key. If the value does not 53 | /// exist, `initial` would be called and the returned value would be 54 | /// associated subsequently. 55 | /// 56 | /// - parameters: 57 | /// - key: An optional key to differentiate different values. 58 | /// - initial: The action that supples an initial value. 59 | /// 60 | /// - returns: The associated value for the specified key. 61 | internal func associatedValue(forKey key: StaticString = #function, initial: (Base) -> T) -> T { 62 | let key = AssociationKey(key) 63 | 64 | if let value = base.associations.value(forKey: key) { 65 | return value 66 | } 67 | 68 | let value = initial(base) 69 | base.associations.setValue(value, forKey: key) 70 | 71 | return value 72 | } 73 | } 74 | 75 | extension NSObjectProtocol { 76 | @nonobjc internal var associations: Associations { 77 | return Associations(self) 78 | } 79 | } 80 | 81 | extension Associations { 82 | /// Retrieve the associated value for the specified key. 83 | /// 84 | /// - parameters: 85 | /// - key: The key. 86 | /// 87 | /// - returns: The associated value, or the default value if no value has been 88 | /// associated with the key. 89 | internal func value(forKey key: AssociationKey) -> Value { 90 | return (objc_getAssociatedObject(base, key.address) as! Value?) ?? key.default 91 | } 92 | 93 | /// Retrieve the associated value for the specified key. 94 | /// 95 | /// - parameters: 96 | /// - key: The key. 97 | /// 98 | /// - returns: The associated value, or `nil` if no value is associated with 99 | /// the key. 100 | internal func value(forKey key: AssociationKey) -> Value? { 101 | return objc_getAssociatedObject(base, key.address) as! Value? 102 | } 103 | 104 | /// Set the associated value for the specified key. 105 | /// 106 | /// - parameters: 107 | /// - value: The value to be associated. 108 | /// - key: The key. 109 | internal func setValue(_ value: Value, forKey key: AssociationKey) { 110 | objc_setAssociatedObject(base, key.address, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 111 | } 112 | 113 | /// Set the associated value for the specified key. 114 | /// 115 | /// - parameters: 116 | /// - value: The value to be associated. 117 | /// - key: The key. 118 | internal func setValue(_ value: Value?, forKey key: AssociationKey) { 119 | objc_setAssociatedObject(base, key.address, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 120 | } 121 | } 122 | 123 | /// Set the associated value for the specified key. 124 | /// 125 | /// - parameters: 126 | /// - value: The value to be associated. 127 | /// - key: The key. 128 | /// - address: The address of the object. 129 | internal func unsafeSetAssociatedValue(_ value: Value?, forKey key: AssociationKey, forObjectAt address: UnsafeRawPointer) { 130 | _rac_objc_setAssociatedObject(address, key.address, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 131 | } 132 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+BindingTarget.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | 4 | extension Reactive where Base: AnyObject { 5 | /// Creates a binding target which uses the lifetime of the object, and 6 | /// weakly references the object so that the supplied `action` is triggered 7 | /// only if the object has not deinitialized. 8 | /// 9 | /// - parameters: 10 | /// - scheduler: An optional scheduler that the binding target uses. If it 11 | /// is not specified, a UI scheduler would be used. 12 | /// - action: The action to consume values from the bindings. 13 | /// 14 | /// - returns: A binding target that holds no strong references to the 15 | /// object. 16 | public func makeBindingTarget(on scheduler: Scheduler = UIScheduler(), _ action: @escaping (Base, U) -> Void) -> BindingTarget { 17 | return BindingTarget(on: scheduler, lifetime: ReactiveCocoa.lifetime(of: base)) { [weak base = self.base] value in 18 | if let base = base { 19 | action(base, value) 20 | } 21 | } 22 | } 23 | } 24 | 25 | #if swift(>=3.2) 26 | extension Reactive where Base: AnyObject { 27 | /// Creates a binding target that writes to the object with the given key path on a 28 | /// `UIScheduler`. 29 | /// 30 | /// - parameters: 31 | /// - keyPath: The key path to be written to. 32 | /// 33 | /// - returns: A binding target. 34 | public subscript(keyPath: ReferenceWritableKeyPath) -> BindingTarget { 35 | return BindingTarget(on: UIScheduler(), lifetime: ReactiveCocoa.lifetime(of: base), object: base, keyPath: keyPath) 36 | } 37 | 38 | /// Creates a binding target that writes to the object with the given key path. 39 | /// 40 | /// - parameters: 41 | /// - keyPath: The key path to be written to. 42 | /// - scheduler: The scheduler to perform the write on. 43 | /// 44 | /// - returns: A binding target. 45 | public subscript(keyPath: ReferenceWritableKeyPath, on scheduler: Scheduler) -> BindingTarget { 46 | return BindingTarget(on: scheduler, lifetime: ReactiveCocoa.lifetime(of: base), object: base, keyPath: keyPath) 47 | } 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+Lifetime.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | 4 | /// Holds the `Lifetime` of the object. 5 | fileprivate let isSwizzledKey = AssociationKey(default: false) 6 | 7 | /// Holds the `Lifetime` of the object. 8 | fileprivate let lifetimeKey = AssociationKey(default: nil) 9 | 10 | /// Holds the `Lifetime.Token` of the object. 11 | fileprivate let lifetimeTokenKey = AssociationKey(default: nil) 12 | 13 | internal func lifetime(of object: AnyObject) -> Lifetime { 14 | if let object = object as? NSObject { 15 | return object.reactive.lifetime 16 | } 17 | 18 | return synchronized(object) { 19 | let associations = Associations(object) 20 | 21 | if let lifetime = associations.value(forKey: lifetimeKey) { 22 | return lifetime 23 | } 24 | 25 | let (lifetime, token) = Lifetime.make() 26 | 27 | associations.setValue(token, forKey: lifetimeTokenKey) 28 | associations.setValue(lifetime, forKey: lifetimeKey) 29 | 30 | return lifetime 31 | } 32 | } 33 | 34 | extension Reactive where Base: AnyObject & NSObjectProtocol { 35 | /// Returns a lifetime that ends when the object is deallocated. 36 | @nonobjc public var lifetime: Lifetime { 37 | return base.synchronized { 38 | if let lifetime = base.associations.value(forKey: lifetimeKey) { 39 | return lifetime 40 | } 41 | 42 | let (lifetime, token) = Lifetime.make() 43 | 44 | let objcClass: AnyClass = (base as AnyObject).objcClass 45 | let objcClassAssociations = Associations(objcClass as AnyObject) 46 | 47 | #if swift(>=4.0) 48 | let deallocSelector = sel_registerName("dealloc") 49 | #else 50 | let deallocSelector = sel_registerName("dealloc")! 51 | #endif 52 | 53 | // Swizzle `-dealloc` so that the lifetime token is released at the 54 | // beginning of the deallocation chain, and only after the KVO `-dealloc`. 55 | synchronized(objcClass) { 56 | // Swizzle the class only if it has not been swizzled before. 57 | if !objcClassAssociations.value(forKey: isSwizzledKey) { 58 | objcClassAssociations.setValue(true, forKey: isSwizzledKey) 59 | 60 | var existingImpl: IMP? = nil 61 | 62 | let newImplBlock: @convention(block) (UnsafeRawPointer) -> Void = { objectRef in 63 | // A custom trampoline of `objc_setAssociatedObject` is used, since 64 | // the imported version has been inserted with ARC calls that would 65 | // mess with the object deallocation chain. 66 | 67 | // Release the lifetime token. 68 | unsafeSetAssociatedValue(nil, forKey: lifetimeTokenKey, forObjectAt: objectRef) 69 | 70 | let impl: IMP 71 | 72 | // Call the existing implementation if one has been caught. Otherwise, 73 | // call the one first available in the superclass hierarchy. 74 | if let existingImpl = existingImpl { 75 | impl = existingImpl 76 | } else { 77 | let superclass: AnyClass = class_getSuperclass(objcClass)! 78 | impl = class_getMethodImplementation(superclass, deallocSelector)! 79 | } 80 | 81 | typealias Impl = @convention(c) (UnsafeRawPointer, Selector) -> Void 82 | unsafeBitCast(impl, to: Impl.self)(objectRef, deallocSelector) 83 | } 84 | 85 | let newImpl = imp_implementationWithBlock(newImplBlock as Any) 86 | 87 | if !class_addMethod(objcClass, deallocSelector, newImpl, "v@:") { 88 | // The class has an existing `dealloc`. Preserve that as `existingImpl`. 89 | let deallocMethod = class_getInstanceMethod(objcClass, deallocSelector)! 90 | 91 | // Store the existing implementation to `existingImpl` to ensure it is 92 | // available before our version is swapped in. 93 | existingImpl = method_getImplementation(deallocMethod) 94 | 95 | // Store the swapped-out implementation to `existingImpl` in case 96 | // the implementation has been changed concurrently. 97 | existingImpl = method_setImplementation(deallocMethod, newImpl) 98 | } 99 | } 100 | } 101 | 102 | base.associations.setValue(token, forKey: lifetimeTokenKey) 103 | base.associations.setValue(lifetime, forKey: lifetimeKey) 104 | 105 | return lifetime 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+ObjCRuntime.swift: -------------------------------------------------------------------------------- 1 | extension NSObject { 2 | /// The class of the instance reported by the ObjC `-class:` message. 3 | /// 4 | /// - note: `type(of:)` might return the runtime subclass, while this property 5 | /// always returns the original class. 6 | @nonobjc internal var objcClass: AnyClass { 7 | return (self as AnyObject).objcClass 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+ReactiveExtensionsProvider.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ReactiveSwift 3 | 4 | extension NSObject: ReactiveExtensionsProvider {} 5 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/NSObject+Synchronizing.swift: -------------------------------------------------------------------------------- 1 | extension NSObjectProtocol { 2 | internal func synchronized(execute: () throws -> Result) rethrows -> Result { 3 | objc_sync_enter(self) 4 | defer { objc_sync_exit(self) } 5 | return try execute() 6 | } 7 | } 8 | 9 | internal func synchronized(_ token: AnyObject, execute: () throws -> Result) rethrows -> Result { 10 | objc_sync_enter(token) 11 | defer { objc_sync_exit(token) } 12 | return try execute() 13 | } 14 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjC+Constants.swift: -------------------------------------------------------------------------------- 1 | // Unavailable selectors in Swift. 2 | internal enum ObjCSelector { 3 | static let forwardInvocation = Selector((("forwardInvocation:"))) 4 | static let methodSignatureForSelector = Selector((("methodSignatureForSelector:"))) 5 | static let getClass = Selector((("class"))) 6 | } 7 | 8 | // Method encoding of the unavailable selectors. 9 | internal enum ObjCMethodEncoding { 10 | static let forwardInvocation = extract("v@:@") 11 | static let methodSignatureForSelector = extract("v@::") 12 | static let getClass = extract("#@:") 13 | 14 | private static func extract(_ string: StaticString) -> UnsafePointer { 15 | return UnsafeRawPointer(string.utf8Start).assumingMemoryBound(to: CChar.self) 16 | } 17 | } 18 | 19 | /// Objective-C type encoding. 20 | /// 21 | /// The enum does not cover all options, but only those that are expressive in 22 | /// Swift. 23 | internal enum ObjCTypeEncoding: Int8 { 24 | case char = 99 25 | case int = 105 26 | case short = 115 27 | case long = 108 28 | case longLong = 113 29 | 30 | case unsignedChar = 67 31 | case unsignedInt = 73 32 | case unsignedShort = 83 33 | case unsignedLong = 76 34 | case unsignedLongLong = 81 35 | 36 | case float = 102 37 | case double = 100 38 | 39 | case bool = 66 40 | 41 | case object = 64 42 | case type = 35 43 | case selector = 58 44 | 45 | case undefined = -1 46 | } 47 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjC+Messages.swift: -------------------------------------------------------------------------------- 1 | // Unavailable classes like `NSInvocation` can still be passed into Swift as 2 | // `AnyClass` and `AnyObject`, and receive messages as `AnyClass` and 3 | // `AnyObject` existentials. 4 | // 5 | // These `@objc` protocols host the method signatures so that they can be used 6 | // with `AnyObject`. 7 | 8 | internal let NSInvocation: AnyClass = NSClassFromString("NSInvocation")! 9 | internal let NSMethodSignature: AnyClass = NSClassFromString("NSMethodSignature")! 10 | 11 | // Signatures defined in `@objc` protocols would be available for ObjC message 12 | // sending via `AnyObject`. 13 | @objc internal protocol ObjCClassReporting { 14 | // An alias for `-class`, which is unavailable in Swift. 15 | @objc(class) 16 | var objcClass: AnyClass! { get } 17 | } 18 | 19 | // Methods of `NSInvocation`. 20 | @objc internal protocol ObjCInvocation { 21 | @objc(setSelector:) 22 | func setSelector(_ selector: Selector) 23 | 24 | @objc(methodSignature) 25 | var objcMethodSignature: AnyObject { get } 26 | 27 | @objc(getArgument:atIndex:) 28 | func copy(to buffer: UnsafeMutableRawPointer?, forArgumentAt index: Int) 29 | 30 | func invoke() 31 | 32 | @objc(invocationWithMethodSignature:) 33 | static func invocation(withMethodSignature signature: AnyObject) -> AnyObject 34 | } 35 | 36 | // Methods of `NSMethodSignature`. 37 | @objc internal protocol ObjCMethodSignature { 38 | var numberOfArguments: UInt { get } 39 | 40 | @objc(getArgumentTypeAtIndex:) 41 | func argumentType(at index: UInt) -> UnsafePointer 42 | 43 | @objc(signatureWithObjCTypes:) 44 | static func signature(withObjCTypes typeEncoding: UnsafePointer) -> AnyObject 45 | } 46 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjC+Runtime.swift: -------------------------------------------------------------------------------- 1 | /// Search in `class` for any method that matches the supplied selector without 2 | /// propagating to the ancestors. 3 | /// 4 | /// - parameters: 5 | /// - class: The class to search the method in. 6 | /// - selector: The selector of the method. 7 | /// 8 | /// - returns: The matching method, or `nil` if none is found. 9 | internal func class_getImmediateMethod(_ `class`: AnyClass, _ selector: Selector) -> Method? { 10 | var total: UInt32 = 0 11 | 12 | if let methods = class_copyMethodList(`class`, &total) { 13 | defer { free(methods) } 14 | 15 | for index in 0 ..< Int(total) { 16 | let method = methods[index] 17 | 18 | if method_getName(method) == selector { 19 | return method 20 | } 21 | } 22 | } 23 | 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjC+RuntimeSubclassing.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | 3 | /// Whether the runtime subclass has already been swizzled. 4 | fileprivate let runtimeSubclassedKey = AssociationKey(default: false) 5 | 6 | /// A known RAC runtime subclass of the instance. `nil` if the runtime subclass 7 | /// has not been requested for the instance before. 8 | fileprivate let knownRuntimeSubclassKey = AssociationKey(default: nil) 9 | 10 | extension NSObject { 11 | /// Swizzle the given selectors. 12 | /// 13 | /// - warning: The swizzling **does not** apply on a per-instance basis. In 14 | /// other words, repetitive swizzling of the same selector would 15 | /// overwrite previous swizzling attempts, despite a different 16 | /// instance being supplied. 17 | /// 18 | /// - parameters: 19 | /// - pairs: Tuples of selectors and the respective implementions to be 20 | /// swapped in. 21 | /// - key: An association key which determines if the swizzling has already 22 | /// been performed. 23 | internal func swizzle(_ pairs: (Selector, Any)..., key hasSwizzledKey: AssociationKey) { 24 | let subclass: AnyClass = swizzleClass(self) 25 | 26 | try! ReactiveCocoa.synchronized(subclass) { 27 | let subclassAssociations = Associations(subclass as AnyObject) 28 | 29 | if !subclassAssociations.value(forKey: hasSwizzledKey) { 30 | subclassAssociations.setValue(true, forKey: hasSwizzledKey) 31 | 32 | for (selector, body) in pairs { 33 | let method = class_getInstanceMethod(subclass, selector)! 34 | let typeEncoding = method_getTypeEncoding(method)! 35 | 36 | if method_getImplementation(method) == _rac_objc_msgForward { 37 | let succeeds = class_addMethod(subclass, selector.interopAlias, imp_implementationWithBlock(body), typeEncoding) 38 | precondition(succeeds, "RAC attempts to swizzle a selector that has message forwarding enabled with a runtime injected implementation. This is unsupported in the current version.") 39 | } else { 40 | let succeeds = class_addMethod(subclass, selector, imp_implementationWithBlock(body), typeEncoding) 41 | precondition(succeeds, "RAC attempts to swizzle a selector that has already a runtime injected implementation. This is unsupported in the current version.") 42 | } 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | /// ISA-swizzle the class of the supplied instance. 50 | /// 51 | /// - note: If the instance has already been isa-swizzled, the swizzling happens 52 | /// in place in the runtime subclass created by external parties. 53 | /// 54 | /// - warning: The swizzling **does not** apply on a per-instance basis. In 55 | /// other words, repetitive swizzling of the same selector would 56 | /// overwrite previous swizzling attempts, despite a different 57 | /// instance being supplied. 58 | /// 59 | /// - parameters: 60 | /// - instance: The instance to be swizzled. 61 | /// 62 | /// - returns: The runtime subclass of the perceived class of the instance. 63 | internal func swizzleClass(_ instance: NSObject) -> AnyClass { 64 | if let knownSubclass = instance.associations.value(forKey: knownRuntimeSubclassKey) { 65 | return knownSubclass 66 | } 67 | 68 | let perceivedClass: AnyClass = instance.objcClass 69 | let realClass: AnyClass = object_getClass(instance)! 70 | let realClassAssociations = Associations(realClass as AnyObject) 71 | 72 | if perceivedClass != realClass { 73 | // If the class is already lying about what it is, it's probably a KVO 74 | // dynamic subclass or something else that we shouldn't subclass at runtime. 75 | synchronized(realClass) { 76 | let isSwizzled = realClassAssociations.value(forKey: runtimeSubclassedKey) 77 | if !isSwizzled { 78 | replaceGetClass(in: realClass, decoy: perceivedClass) 79 | realClassAssociations.setValue(true, forKey: runtimeSubclassedKey) 80 | } 81 | } 82 | 83 | return realClass 84 | } else { 85 | let name = subclassName(of: perceivedClass) 86 | let subclass: AnyClass = name.withCString { cString in 87 | if let existingClass = objc_getClass(cString) as! AnyClass? { 88 | return existingClass 89 | } else { 90 | let subclass: AnyClass = objc_allocateClassPair(perceivedClass, cString, 0)! 91 | replaceGetClass(in: subclass, decoy: perceivedClass) 92 | objc_registerClassPair(subclass) 93 | return subclass 94 | } 95 | } 96 | 97 | object_setClass(instance, subclass) 98 | instance.associations.setValue(subclass, forKey: knownRuntimeSubclassKey) 99 | return subclass 100 | } 101 | } 102 | 103 | private func subclassName(of class: AnyClass) -> String { 104 | return String(cString: class_getName(`class`)).appending("_RACSwift") 105 | } 106 | 107 | /// Swizzle the `-class` and `+class` methods. 108 | /// 109 | /// - parameters: 110 | /// - class: The class to swizzle. 111 | /// - perceivedClass: The class to be reported by the methods. 112 | private func replaceGetClass(in class: AnyClass, decoy perceivedClass: AnyClass) { 113 | let getClass: @convention(block) (UnsafeRawPointer?) -> AnyClass = { _ in 114 | return perceivedClass 115 | } 116 | 117 | let impl = imp_implementationWithBlock(getClass as Any) 118 | 119 | _ = class_replaceMethod(`class`, 120 | ObjCSelector.getClass, 121 | impl, 122 | ObjCMethodEncoding.getClass) 123 | 124 | _ = class_replaceMethod(object_getClass(`class`), 125 | ObjCSelector.getClass, 126 | impl, 127 | ObjCMethodEncoding.getClass) 128 | } 129 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjC+Selector.swift: -------------------------------------------------------------------------------- 1 | extension Selector { 2 | /// `self` as a pointer. It is uniqued across instances, similar to 3 | /// `StaticString`. 4 | internal var utf8Start: UnsafePointer { 5 | return unsafeBitCast(self, to: UnsafePointer.self) 6 | } 7 | 8 | /// An alias of `self`, used in method interception. 9 | internal var alias: Selector { 10 | return prefixing("rac0_") 11 | } 12 | 13 | /// An alias of `self`, used in method interception specifically for 14 | /// preserving (if found) an immediate implementation of `self` in the 15 | /// runtime subclass. 16 | internal var interopAlias: Selector { 17 | return prefixing("rac1_") 18 | } 19 | 20 | /// An alias of `self`, used for delegate proxies. 21 | internal var delegateProxyAlias: Selector { 22 | return prefixing("rac2_") 23 | } 24 | 25 | internal func prefixing(_ prefix: StaticString) -> Selector { 26 | let length = Int(strlen(utf8Start)) 27 | let prefixedLength = length + prefix.utf8CodeUnitCount 28 | 29 | let asciiPrefix = UnsafeRawPointer(prefix.utf8Start).assumingMemoryBound(to: Int8.self) 30 | 31 | let cString = UnsafeMutablePointer.allocate(capacity: prefixedLength + 1) 32 | defer { 33 | cString.deinitialize() 34 | cString.deallocate(capacity: prefixedLength + 1) 35 | } 36 | 37 | cString.initialize(from: asciiPrefix, count: prefix.utf8CodeUnitCount) 38 | (cString + prefix.utf8CodeUnitCount).initialize(from: utf8Start, count: length) 39 | (cString + prefixedLength).initialize(to: Int8(UInt8(ascii: "\0"))) 40 | 41 | return sel_registerName(cString) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjCRuntimeAliases.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | extern const IMP _rac_objc_msgForward; 7 | 8 | /// A trampoline of `objc_setAssociatedObject` that is made to circumvent the 9 | /// reference counting calls in the imported version in Swift. 10 | void _rac_objc_setAssociatedObject(const void* object, const void* key, id _Nullable value, objc_AssociationPolicy policy); 11 | 12 | NS_ASSUME_NONNULL_END 13 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ObjCRuntimeAliases.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | const IMP _rac_objc_msgForward = _objc_msgForward; 5 | 6 | void _rac_objc_setAssociatedObject(const void* object, const void* key, id value, objc_AssociationPolicy policy) { 7 | __unsafe_unretained id obj = (__bridge typeof(obj)) object; 8 | objc_setAssociatedObject(obj, key, value, policy); 9 | } 10 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ReactiveCocoa.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for ReactiveCocoa. 4 | FOUNDATION_EXPORT double ReactiveCocoaVersionNumber; 5 | 6 | //! Project version string for ReactiveCocoa. 7 | FOUNDATION_EXPORT const unsigned char ReactiveCocoaVersionString[]; 8 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/ReactiveSwift+Lifetime.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | 3 | extension Signal { 4 | /// Forward events from `self` until `object` deinitializes, at which point the 5 | /// returned signal will complete. 6 | /// 7 | /// - parameters: 8 | /// - object: An object of which the deinitialization would complete the returned 9 | /// `Signal`. Both Objective-C and native Swift objects are supported. 10 | /// 11 | /// - returns: A signal that will deliver events until `object` deinitializes. 12 | public func take(duringLifetimeOf object: AnyObject) -> Signal { 13 | return take(during: lifetime(of: object)) 14 | } 15 | } 16 | 17 | extension SignalProducer { 18 | /// Forward events from `self` until `object` deinitializes, at which point the 19 | /// returned producer will complete. 20 | /// 21 | /// - parameters: 22 | /// - object: An object of which the deinitialization would complete the returned 23 | /// `Signal`. Both Objective-C and native Swift objects are supported. 24 | /// 25 | /// - returns: A producer that will deliver events until `object` deinitializes. 26 | public func take(duringLifetimeOf object: AnyObject) -> SignalProducer { 27 | return lift { $0.take(duringLifetimeOf: object) } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/Shared/NSLayoutConstraint.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | 3 | #if os(macOS) 4 | import AppKit 5 | #else 6 | import UIKit 7 | #endif 8 | 9 | extension Reactive where Base: NSLayoutConstraint { 10 | 11 | /// Sets the constant. 12 | public var constant: BindingTarget { 13 | return makeBindingTarget { $0.constant = $1 } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/ReusableComponents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | @objc public protocol Reusable: class { 6 | func prepareForReuse() 7 | } 8 | 9 | extension Reactive where Base: NSObject, Base: Reusable { 10 | public var prepareForReuse: Signal<(), NoError> { 11 | return trigger(for: #selector(base.prepareForReuse)) 12 | } 13 | } 14 | 15 | extension UITableViewCell: Reusable {} 16 | extension UITableViewHeaderFooterView: Reusable {} 17 | extension UICollectionReusableView: Reusable {} 18 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIActivityIndicatorView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIActivityIndicatorView { 5 | /// Sets whether the activity indicator should be animating. 6 | public var isAnimating: BindingTarget { 7 | return makeBindingTarget { $1 ? $0.startAnimating() : $0.stopAnimating() } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIBarButtonItem.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIBarButtonItem { 5 | /// The current associated action of `self`. 6 | private var associatedAction: Atomic<(action: CocoaAction, disposable: Disposable?)?> { 7 | return associatedValue { _ in Atomic(nil) } 8 | } 9 | 10 | /// The action to be triggered when the button is pressed. It also controls 11 | /// the enabled state of the button. 12 | public var pressed: CocoaAction? { 13 | get { 14 | return associatedAction.value?.action 15 | } 16 | 17 | nonmutating set { 18 | base.target = newValue 19 | base.action = newValue.map { _ in CocoaAction.selector } 20 | 21 | associatedAction 22 | .swap(newValue.map { action in 23 | let disposable = isEnabled <~ action.isEnabled 24 | return (action, disposable) 25 | })? 26 | .disposable?.dispose() 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIBarItem.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIBarItem { 5 | /// Sets whether the bar item is enabled. 6 | public var isEnabled: BindingTarget { 7 | return makeBindingTarget { $0.isEnabled = $1 } 8 | } 9 | 10 | /// Sets image of bar item. 11 | public var image: BindingTarget { 12 | return makeBindingTarget { $0.image = $1 } 13 | } 14 | 15 | /// Sets the title of bar item. 16 | public var title: BindingTarget { 17 | return makeBindingTarget { $0.title = $1 } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIButton.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIButton { 5 | /// The action to be triggered when the button is pressed. It also controls 6 | /// the enabled state of the button. 7 | public var pressed: CocoaAction? { 8 | get { 9 | return associatedAction.withValue { info in 10 | return info.flatMap { info in 11 | return info.controlEvents == pressEvent ? info.action : nil 12 | } 13 | } 14 | } 15 | 16 | nonmutating set { 17 | setAction(newValue, for: pressEvent) 18 | } 19 | } 20 | 21 | private var pressEvent: UIControlEvents { 22 | if #available(iOS 9.0, tvOS 9.0, *) { 23 | return .primaryActionTriggered 24 | } else { 25 | return .touchUpInside 26 | } 27 | } 28 | 29 | /// Sets the title of the button for its normal state. 30 | public var title: BindingTarget { 31 | return makeBindingTarget { $0.setTitle($1, for: .normal) } 32 | } 33 | 34 | /// Sets the title of the button for the specified state. 35 | public func title(for state: UIControlState) -> BindingTarget { 36 | return makeBindingTarget { $0.setTitle($1, for: state) } 37 | } 38 | 39 | /// Sets the image of the button for the specified state. 40 | public func image(for state: UIControlState) -> BindingTarget { 41 | return makeBindingTarget { $0.setImage($1, for: state) } 42 | } 43 | 44 | /// Sets the image of the button for the .normal state 45 | public var image: BindingTarget { 46 | return image(for: .normal) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UICollectionView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UICollectionView { 5 | public var reloadData: BindingTarget<()> { 6 | return makeBindingTarget { base, _ in base.reloadData() } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIControl.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | import enum Result.NoError 4 | 5 | extension Reactive where Base: UIControl { 6 | /// The current associated action of `self`, with its registered event mask 7 | /// and its disposable. 8 | internal var associatedAction: Atomic<(action: CocoaAction, controlEvents: UIControlEvents, disposable: Disposable)?> { 9 | return associatedValue { _ in Atomic(nil) } 10 | } 11 | 12 | /// Set the associated action of `self` to `action`, and register it for the 13 | /// control events specified by `controlEvents`. 14 | /// 15 | /// - parameters: 16 | /// - action: The action to be associated. 17 | /// - controlEvents: The control event mask. 18 | /// - disposable: An outside disposable that will be bound to the scope of 19 | /// the given `action`. 20 | internal func setAction(_ action: CocoaAction?, for controlEvents: UIControlEvents, disposable: Disposable? = nil) { 21 | associatedAction.modify { associatedAction in 22 | associatedAction?.disposable.dispose() 23 | 24 | if let action = action { 25 | base.addTarget(action, action: CocoaAction.selector, for: controlEvents) 26 | 27 | let compositeDisposable = CompositeDisposable() 28 | compositeDisposable += isEnabled <~ action.isEnabled 29 | compositeDisposable += { [weak base = self.base] in 30 | base?.removeTarget(action, action: CocoaAction.selector, for: controlEvents) 31 | } 32 | compositeDisposable += disposable 33 | 34 | associatedAction = (action, controlEvents, ScopedDisposable(compositeDisposable)) 35 | } else { 36 | associatedAction = nil 37 | } 38 | } 39 | } 40 | 41 | /// Create a signal which sends a `value` event for each of the specified 42 | /// control events. 43 | /// 44 | /// - note: If you mean to observe the **value** of `self` with regard to a particular 45 | /// control event, `mapControlEvents(_:_:)` should be used instead. 46 | /// 47 | /// - parameters: 48 | /// - controlEvents: The control event mask. 49 | /// 50 | /// - returns: A signal that sends the control each time the control event occurs. 51 | public func controlEvents(_ controlEvents: UIControlEvents) -> Signal { 52 | return mapControlEvents(controlEvents, { $0 }) 53 | } 54 | 55 | /// Create a signal which sends a `value` event for each of the specified 56 | /// control events. 57 | /// 58 | /// - important: You should use `mapControlEvents` in general unless the state of 59 | /// the control — e.g. `text`, `state` — is not concerned. In other 60 | /// words, you should avoid using `map` on a control event signal to 61 | /// extract the state from the control. 62 | /// 63 | /// - note: For observations that could potentially manipulate the first responder 64 | /// status of `base`, `mapControlEvents(_:_:)` is made aware of the potential 65 | /// recursion induced by UIKit and would collect the values for the control 66 | /// events accordingly using the given transform. 67 | /// 68 | /// - parameters: 69 | /// - controlEvents: The control event mask. 70 | /// - transform: A transform to reduce `Base`. 71 | /// 72 | /// - returns: A signal that sends the reduced value from the control each time the 73 | /// control event occurs. 74 | public func mapControlEvents(_ controlEvents: UIControlEvents, _ transform: @escaping (Base) -> Value) -> Signal { 75 | return Signal { observer, signalLifetime in 76 | let receiver = CocoaTarget(observer) { transform($0 as! Base) } 77 | base.addTarget(receiver, 78 | action: #selector(receiver.invoke), 79 | for: controlEvents) 80 | 81 | let disposable = lifetime.ended.observeCompleted(observer.sendCompleted) 82 | 83 | signalLifetime.observeEnded { [weak base] in 84 | disposable?.dispose() 85 | 86 | base?.removeTarget(receiver, 87 | action: #selector(receiver.invoke), 88 | for: controlEvents) 89 | } 90 | } 91 | } 92 | 93 | @available(*, unavailable, renamed: "controlEvents(_:)") 94 | public func trigger(for controlEvents: UIControlEvents) -> Signal<(), NoError> { 95 | fatalError() 96 | } 97 | 98 | /// Sets whether the control is enabled. 99 | public var isEnabled: BindingTarget { 100 | return makeBindingTarget { $0.isEnabled = $1 } 101 | } 102 | 103 | /// Sets whether the control is selected. 104 | public var isSelected: BindingTarget { 105 | return makeBindingTarget { $0.isSelected = $1 } 106 | } 107 | 108 | /// Sets whether the control is highlighted. 109 | public var isHighlighted: BindingTarget { 110 | return makeBindingTarget { $0.isHighlighted = $1 } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIGestureRecognizer.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | import enum Result.NoError 4 | 5 | extension Reactive where Base: UIGestureRecognizer { 6 | /// Create a signal which sends a `next` event for each gesture event 7 | /// 8 | /// - returns: A trigger signal. 9 | public var stateChanged: Signal { 10 | return Signal { observer, signalLifetime in 11 | let receiver = CocoaTarget(observer) { gestureRecognizer in 12 | return gestureRecognizer as! Base 13 | } 14 | base.addTarget(receiver, action: #selector(receiver.invoke)) 15 | 16 | let disposable = lifetime.ended.observeCompleted(observer.sendCompleted) 17 | 18 | signalLifetime.observeEnded { [weak base] in 19 | disposable?.dispose() 20 | base?.removeTarget(receiver, action: #selector(receiver.invoke)) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIImageView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIImageView { 5 | /// Sets the image of the image view. 6 | public var image: BindingTarget { 7 | return makeBindingTarget { $0.image = $1 } 8 | } 9 | 10 | /// Sets the image of the image view for its highlighted state. 11 | public var highlightedImage: BindingTarget { 12 | return makeBindingTarget { $0.highlightedImage = $1 } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UILabel.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UILabel { 5 | /// Sets the text of the label. 6 | public var text: BindingTarget { 7 | return makeBindingTarget { $0.text = $1 } 8 | } 9 | 10 | /// Sets the attributed text of the label. 11 | public var attributedText: BindingTarget { 12 | return makeBindingTarget { $0.attributedText = $1 } 13 | } 14 | 15 | /// Sets the color of the text of the label. 16 | public var textColor: BindingTarget { 17 | return makeBindingTarget { $0.textColor = $1 } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UINavigationItem.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UINavigationItem { 5 | /// Sets the title of the navigation item. 6 | public var title: BindingTarget { 7 | return makeBindingTarget { $0.title = $1 } 8 | } 9 | 10 | #if os(iOS) 11 | /// Sets the prompt of the navigation item. 12 | public var prompt: BindingTarget { 13 | return makeBindingTarget { $0.prompt = $1 } 14 | } 15 | #endif 16 | } 17 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIProgressView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIProgressView { 5 | /// Sets the relative progress to be reflected by the progress view. 6 | public var progress: BindingTarget { 7 | return makeBindingTarget { $0.progress = $1 } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIScrollView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIScrollView { 5 | /// Sets the content inset of the scroll view. 6 | public var contentInset: BindingTarget { 7 | return makeBindingTarget { $0.contentInset = $1 } 8 | } 9 | 10 | /// Sets the scroll indicator insets of the scroll view. 11 | public var scrollIndicatorInsets: BindingTarget { 12 | return makeBindingTarget { $0.scrollIndicatorInsets = $1 } 13 | } 14 | 15 | /// Sets whether scrolling the scroll view is enabled. 16 | public var isScrollEnabled: BindingTarget { 17 | return makeBindingTarget { $0.isScrollEnabled = $1 } 18 | } 19 | 20 | /// Sets the zoom scale of the scroll view. 21 | public var zoomScale: BindingTarget { 22 | return makeBindingTarget { $0.zoomScale = $1 } 23 | } 24 | 25 | /// Sets the minimum zoom scale of the scroll view. 26 | public var minimumZoomScale: BindingTarget { 27 | return makeBindingTarget { $0.minimumZoomScale = $1 } 28 | } 29 | 30 | /// Sets the maximum zoom scale of the scroll view. 31 | public var maximumZoomScale: BindingTarget { 32 | return makeBindingTarget { $0.maximumZoomScale = $1 } 33 | } 34 | 35 | #if os(iOS) 36 | /// Sets whether the scroll view scrolls to the top when the menu is tapped. 37 | public var scrollsToTop: BindingTarget { 38 | return makeBindingTarget { $0.scrollsToTop = $1 } 39 | } 40 | #endif 41 | } 42 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UISegmentedControl.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | extension Reactive where Base: UISegmentedControl { 6 | /// Changes the selected segment of the segmented control. 7 | public var selectedSegmentIndex: BindingTarget { 8 | return makeBindingTarget { $0.selectedSegmentIndex = $1 } 9 | } 10 | 11 | /// A signal of indexes of selections emitted by the segmented control. 12 | public var selectedSegmentIndexes: Signal { 13 | return mapControlEvents(.valueChanged) { $0.selectedSegmentIndex } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UITabBarItem.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UITabBarItem { 5 | /// Sets the badge value of the tab bar item. 6 | public var badgeValue: BindingTarget { 7 | return makeBindingTarget { $0.badgeValue = $1 } 8 | } 9 | 10 | 11 | /// Sets the badge color of the tab bar item. 12 | @available(iOS 10, *) 13 | @available(tvOS 10, *) 14 | public var badgeColor: BindingTarget { 15 | return makeBindingTarget { $0.badgeColor = $1 } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UITableView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UITableView { 5 | public var reloadData: BindingTarget<()> { 6 | return makeBindingTarget { base, _ in base.reloadData() } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UITextField.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | extension Reactive where Base: UITextField { 6 | /// Sets the text of the text field. 7 | public var text: BindingTarget { 8 | return makeBindingTarget { $0.text = $1 } 9 | } 10 | 11 | /// A signal of text values emitted by the text field upon end of editing. 12 | /// 13 | /// - note: To observe text values that change on all editing events, 14 | /// see `continuousTextValues`. 15 | public var textValues: Signal { 16 | return mapControlEvents([.editingDidEnd, .editingDidEndOnExit]) { $0.text } 17 | } 18 | 19 | /// A signal of text values emitted by the text field upon any changes. 20 | /// 21 | /// - note: To observe text values only when editing ends, see `textValues`. 22 | public var continuousTextValues: Signal { 23 | return mapControlEvents(.allEditingEvents) { $0.text } 24 | } 25 | 26 | /// Sets the attributed text of the text field. 27 | public var attributedText: BindingTarget { 28 | return makeBindingTarget { $0.attributedText = $1 } 29 | } 30 | 31 | /// Sets the placeholder text of the text field. 32 | public var placeholder: BindingTarget { 33 | return makeBindingTarget { $0.placeholder = $1 } 34 | } 35 | 36 | /// Sets the textColor of the text field. 37 | public var textColor: BindingTarget { 38 | return makeBindingTarget { $0.textColor = $1 } 39 | } 40 | 41 | /// A signal of attributed text values emitted by the text field upon end of editing. 42 | /// 43 | /// - note: To observe attributed text values that change on all editing events, 44 | /// see `continuousAttributedTextValues`. 45 | public var attributedTextValues: Signal { 46 | return mapControlEvents([.editingDidEnd, .editingDidEndOnExit]) { $0.attributedText } 47 | } 48 | 49 | /// A signal of attributed text values emitted by the text field upon any changes. 50 | /// 51 | /// - note: To observe attributed text values only when editing ends, see `attributedTextValues`. 52 | public var continuousAttributedTextValues: Signal { 53 | return mapControlEvents(.allEditingEvents) { $0.attributedText } 54 | } 55 | 56 | /// Sets the secure text entry attribute on the text field. 57 | public var isSecureTextEntry: BindingTarget { 58 | return makeBindingTarget { $0.isSecureTextEntry = $1 } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UITextView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | import enum Result.NoError 4 | 5 | private class TextViewDelegateProxy: DelegateProxy, UITextViewDelegate { 6 | @objc func textViewDidChangeSelection(_ textView: UITextView) { 7 | forwardee?.textViewDidChangeSelection?(textView) 8 | } 9 | } 10 | 11 | extension Reactive where Base: UITextView { 12 | private var proxy: TextViewDelegateProxy { 13 | return .proxy(for: base, 14 | setter: #selector(setter: base.delegate), 15 | getter: #selector(getter: base.delegate)) 16 | } 17 | 18 | /// Sets the text of the text view. 19 | public var text: BindingTarget { 20 | return makeBindingTarget { $0.text = $1 } 21 | } 22 | 23 | private func textValues(forName name: NSNotification.Name) -> Signal { 24 | return NotificationCenter.default 25 | .reactive 26 | .notifications(forName: name, object: base) 27 | .take(during: lifetime) 28 | .map { ($0.object as! UITextView).text! } 29 | } 30 | 31 | /// A signal of text values emitted by the text view upon end of editing. 32 | /// 33 | /// - note: To observe text values that change on all editing events, 34 | /// see `continuousTextValues`. 35 | public var textValues: Signal { 36 | return textValues(forName: .UITextViewTextDidEndEditing) 37 | } 38 | 39 | /// A signal of text values emitted by the text view upon any changes. 40 | /// 41 | /// - note: To observe text values only when editing ends, see `textValues`. 42 | public var continuousTextValues: Signal { 43 | return textValues(forName: .UITextViewTextDidChange) 44 | } 45 | 46 | /// Sets the attributed text of the text view. 47 | public var attributedText: BindingTarget { 48 | return makeBindingTarget { $0.attributedText = $1 } 49 | } 50 | 51 | private func attributedTextValues(forName name: NSNotification.Name) -> Signal { 52 | return NotificationCenter.default 53 | .reactive 54 | .notifications(forName: name, object: base) 55 | .take(during: lifetime) 56 | .map { ($0.object as! UITextView).attributedText! } 57 | } 58 | 59 | /// A signal of attributed text values emitted by the text view upon end of editing. 60 | /// 61 | /// - note: To observe attributed text values that change on all editing events, 62 | /// see `continuousAttributedTextValues`. 63 | public var attributedTextValues: Signal { 64 | return attributedTextValues(forName: .UITextViewTextDidEndEditing) 65 | } 66 | 67 | /// A signal of attributed text values emitted by the text view upon any changes. 68 | /// 69 | /// - note: To observe text values only when editing ends, see `attributedTextValues`. 70 | public var continuousAttributedTextValues: Signal { 71 | return attributedTextValues(forName: .UITextViewTextDidChange) 72 | } 73 | 74 | /// A signal of range values emitted by the text view upon any selection change. 75 | public var selectedRangeValues: Signal { 76 | return proxy.intercept(#selector(UITextViewDelegate.textViewDidChangeSelection)) 77 | .map { [unowned base] in base.selectedRange } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/UIView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | extension Reactive where Base: UIView { 5 | /// Sets the alpha value of the view. 6 | public var alpha: BindingTarget { 7 | return makeBindingTarget { $0.alpha = $1 } 8 | } 9 | 10 | /// Sets whether the view is hidden. 11 | public var isHidden: BindingTarget { 12 | return makeBindingTarget { $0.isHidden = $1 } 13 | } 14 | 15 | /// Sets whether the view accepts user interactions. 16 | public var isUserInteractionEnabled: BindingTarget { 17 | return makeBindingTarget { $0.isUserInteractionEnabled = $1 } 18 | } 19 | 20 | /// Sets the background color of the view. 21 | public var backgroundColor: BindingTarget { 22 | return makeBindingTarget { $0.backgroundColor = $1 } 23 | } 24 | 25 | /// Sets the tintColor of the view 26 | public var tintColor: BindingTarget { 27 | return makeBindingTarget { $0.tintColor = $1 } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIDatePicker.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | extension Reactive where Base: UIDatePicker { 6 | /// Sets the date of the date picker. 7 | public var date: BindingTarget { 8 | return makeBindingTarget { $0.date = $1 } 9 | } 10 | 11 | /// A signal of dates emitted by the date picker. 12 | public var dates: Signal { 13 | return mapControlEvents(.valueChanged) { $0.date } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIFeedbackGenerator.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | @available(iOS 10.0, *) 5 | extension Reactive where Base: UIFeedbackGenerator { 6 | /// Prepares the feedback generator. 7 | public var prepare: BindingTarget<()> { 8 | return makeBindingTarget { generator, _ in 9 | generator.prepare() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIImpact​Feedback​Generator.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | @available(iOS 10.0, *) 5 | extension Reactive where Base: UIImpactFeedbackGenerator { 6 | /// Triggers the feedback. 7 | public var impactOccurred: BindingTarget<()> { 8 | return makeBindingTarget { generator, _ in 9 | generator.impactOccurred() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIKeyboard.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | /// The context of an upcoming change in the frame of the system keyboard. 6 | public struct KeyboardChangeContext { 7 | private let base: [AnyHashable: Any] 8 | 9 | /// The current frame of the system keyboard. 10 | public var beginFrame: CGRect { 11 | return base[UIKeyboardFrameBeginUserInfoKey] as! CGRect 12 | } 13 | 14 | /// The final frame of the system keyboard. 15 | public var endFrame: CGRect { 16 | return base[UIKeyboardFrameEndUserInfoKey] as! CGRect 17 | } 18 | 19 | /// The animation curve which the system keyboard will use to animate the 20 | /// change in its frame. 21 | public var animationCurve: UIViewAnimationCurve { 22 | let value = base[UIKeyboardAnimationCurveUserInfoKey] as! NSNumber 23 | return UIViewAnimationCurve(rawValue: value.intValue)! 24 | } 25 | 26 | /// The duration in which the system keyboard expects to animate the change in 27 | /// its frame. 28 | public var animationDuration: Double { 29 | return base[UIKeyboardAnimationDurationUserInfoKey] as! Double 30 | } 31 | 32 | /// Indicates whether the change is triggered locally. Used in iPad 33 | /// multitasking, where all foreground apps would be notified of any changes 34 | /// in the system keyboard's frame. 35 | @available(iOS 9.0, *) 36 | public var isLocal: Bool { 37 | return base[UIKeyboardIsLocalUserInfoKey] as! Bool 38 | } 39 | 40 | fileprivate init(_ userInfo: [AnyHashable: Any]) { 41 | base = userInfo 42 | } 43 | } 44 | 45 | extension Reactive where Base: NotificationCenter { 46 | /// Create a `Signal` that notifies whenever the system keyboard announces an 47 | /// upcoming change in its frame. 48 | /// 49 | /// - returns: A `Signal` that emits the context of every change in the 50 | /// system keyboard's frame. 51 | public var keyboardChange: Signal { 52 | return notifications(forName: .UIKeyboardWillChangeFrame) 53 | .map { notification in KeyboardChangeContext(notification.userInfo!) } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UINotification​Feedback​Generator.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | @available(iOS 10.0, *) 5 | extension Reactive where Base: UINotificationFeedbackGenerator { 6 | /// Triggers the feedback. 7 | public var notificationOccurred: BindingTarget { 8 | return makeBindingTarget { $0.notificationOccurred($1) } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIPickerView.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | private class PickerViewDelegateProxy: DelegateProxy, UIPickerViewDelegate { 6 | @objc func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 7 | forwardee?.pickerView?(pickerView, didSelectRow: row, inComponent: component) 8 | } 9 | } 10 | 11 | extension Reactive where Base: UIPickerView { 12 | 13 | private var proxy: PickerViewDelegateProxy { 14 | return .proxy(for: base, 15 | setter: #selector(setter: base.delegate), 16 | getter: #selector(getter: base.delegate)) 17 | } 18 | 19 | /// Sets the selected row in the specified component, without animating the 20 | /// position. 21 | public func selectedRow(inComponent component: Int) -> BindingTarget { 22 | return makeBindingTarget { $0.selectRow($1, inComponent: component, animated: false) } 23 | } 24 | 25 | /// Reloads all components 26 | public var reloadAllComponents: BindingTarget<()> { 27 | return makeBindingTarget { base, _ in base.reloadAllComponents() } 28 | } 29 | 30 | /// Reloads the specified component 31 | public var reloadComponent: BindingTarget { 32 | return makeBindingTarget { $0.reloadComponent($1) } 33 | } 34 | 35 | /// Create a signal which sends a `value` event for each row selection 36 | /// 37 | /// - returns: A trigger signal. 38 | public var selections: Signal<(row: Int, component: Int), NoError> { 39 | return proxy.intercept(#selector(UIPickerViewDelegate.pickerView(_:didSelectRow:inComponent:))) 40 | .map { (row: $0[1] as! Int, component: $0[2] as! Int) } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIRefreshControl.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | extension Reactive where Base: UIRefreshControl { 6 | /// Sets whether the refresh control should be refreshing. 7 | public var isRefreshing: BindingTarget { 8 | return makeBindingTarget { $1 ? $0.beginRefreshing() : $0.endRefreshing() } 9 | } 10 | 11 | /// Sets the attributed title of the refresh control. 12 | public var attributedTitle: BindingTarget { 13 | return makeBindingTarget { $0.attributedTitle = $1 } 14 | } 15 | 16 | /// The action to be triggered when the refresh control is refreshed. It 17 | /// also controls the enabled and refreshing states of the refresh control. 18 | public var refresh: CocoaAction? { 19 | get { 20 | return associatedAction.withValue { info in 21 | return info.flatMap { info in 22 | return info.controlEvents == .valueChanged ? info.action : nil 23 | } 24 | } 25 | } 26 | 27 | nonmutating set { 28 | let disposable = newValue.flatMap { isRefreshing <~ $0.isExecuting } 29 | setAction(newValue, for: .valueChanged, disposable: disposable) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UISearchBar.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | private class SearchBarDelegateProxy: DelegateProxy, UISearchBarDelegate { 6 | @objc func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { 7 | forwardee?.searchBarTextDidEndEditing?(searchBar) 8 | } 9 | 10 | @objc func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { 11 | forwardee?.searchBar?(searchBar, textDidChange: searchText) 12 | } 13 | 14 | @objc func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { 15 | forwardee?.searchBarCancelButtonClicked?(searchBar) 16 | } 17 | 18 | @objc func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 19 | forwardee?.searchBarSearchButtonClicked?(searchBar) 20 | } 21 | 22 | @objc func searchBarBookmarkButtonClicked(_ searchBar: UISearchBar) { 23 | forwardee?.searchBarBookmarkButtonClicked?(searchBar) 24 | } 25 | 26 | @objc func searchBarResultsListButtonClicked(_ searchBar: UISearchBar) { 27 | forwardee?.searchBarResultsListButtonClicked?(searchBar) 28 | } 29 | 30 | @objc func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { 31 | forwardee?.searchBar?(searchBar, selectedScopeButtonIndexDidChange: selectedScope) 32 | } 33 | } 34 | 35 | extension Reactive where Base: UISearchBar { 36 | private var proxy: SearchBarDelegateProxy { 37 | return .proxy(for: base, 38 | setter: #selector(setter: base.delegate), 39 | getter: #selector(getter: base.delegate)) 40 | } 41 | 42 | /// Sets the text of the search bar. 43 | public var text: BindingTarget { 44 | return makeBindingTarget { $0.text = $1 } 45 | } 46 | 47 | /// Sets the selected scope button index of the search bar. 48 | public var selectedScopeButtonIndex: BindingTarget { 49 | return makeBindingTarget { $0.selectedScopeButtonIndex = $1 } 50 | } 51 | 52 | /// A signal of text values emitted by the search bar upon end of editing. 53 | /// 54 | /// - note: To observe text values that change on all editing events, 55 | /// see `continuousTextValues`. 56 | public var textValues: Signal { 57 | return proxy.intercept(#selector(UISearchBarDelegate.searchBarTextDidEndEditing)) 58 | .map { [unowned base] in base.text } 59 | } 60 | 61 | /// A signal of text values emitted by the search bar upon any changes. 62 | /// 63 | /// - note: To observe text values only when editing ends, see `textValues`. 64 | public var continuousTextValues: Signal { 65 | return proxy.intercept(#selector(proxy.searchBar(_:textDidChange:))) 66 | .map { [unowned base] in base.text } 67 | } 68 | 69 | /// A signal of the latest selected scope button index upon any user selection. 70 | public var selectedScopeButtonIndices: Signal { 71 | return proxy.intercept(#selector(proxy.searchBar(_:selectedScopeButtonIndexDidChange:))) 72 | .map { $0[1] as! Int } 73 | } 74 | 75 | /// A void signal emitted by the search bar upon any click on the cancel button 76 | public var cancelButtonClicked: Signal { 77 | return proxy.intercept(#selector(proxy.searchBarCancelButtonClicked)) 78 | } 79 | 80 | /// A void signal emitted by the search bar upon any click on the search button 81 | public var searchButtonClicked: Signal { 82 | return proxy.intercept(#selector(proxy.searchBarSearchButtonClicked(_:))) 83 | } 84 | 85 | /// A void signal emitted by the search bar upon any click on the bookmark button 86 | public var bookmarkButtonClicked: Signal { 87 | return proxy.intercept(#selector(proxy.searchBarBookmarkButtonClicked)) 88 | } 89 | 90 | /// A void signal emitted by the search bar upon any click on the bookmark button 91 | public var resultsListButtonClicked: Signal { 92 | return proxy.intercept(#selector(proxy.searchBarResultsListButtonClicked)) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UISelection​Feedback​Generator.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import UIKit 3 | 4 | @available(iOS 10.0, *) 5 | extension Reactive where Base: UISelectionFeedbackGenerator { 6 | /// Triggers the feedback. 7 | public var selectionChanged: BindingTarget<()> { 8 | return makeBindingTarget { generator, _ in 9 | generator.selectionChanged() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UISlider.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | extension Reactive where Base: UISlider { 6 | 7 | /// Sets slider's value. 8 | public var value: BindingTarget { 9 | return makeBindingTarget { $0.value = $1 } 10 | } 11 | 12 | /// Sets slider's minimum value. 13 | public var minimumValue: BindingTarget { 14 | return makeBindingTarget { $0.minimumValue = $1 } 15 | } 16 | 17 | /// Sets slider's maximum value. 18 | public var maximumValue: BindingTarget { 19 | return makeBindingTarget { $0.maximumValue = $1 } 20 | } 21 | 22 | /// A signal of float values emitted by the slider while being dragged by 23 | /// the user. 24 | /// 25 | /// - note: If slider's `isContinuous` property is `false` then values are 26 | /// sent only when user releases the slider. 27 | public var values: Signal { 28 | return mapControlEvents(.valueChanged) { $0.value } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UIStepper.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ReactiveSwift 3 | import enum Result.NoError 4 | 5 | extension Reactive where Base: UIStepper { 6 | 7 | /// Sets the stepper's value. 8 | public var value: BindingTarget { 9 | return makeBindingTarget { $0.value = $1 } 10 | } 11 | 12 | /// Sets stepper's minimum value. 13 | public var minimumValue: BindingTarget { 14 | return makeBindingTarget { $0.minimumValue = $1 } 15 | } 16 | 17 | /// Sets stepper's maximum value. 18 | public var maximumValue: BindingTarget { 19 | return makeBindingTarget { $0.maximumValue = $1 } 20 | } 21 | 22 | /// A signal of double values emitted by the stepper upon each user's 23 | /// interaction. 24 | public var values: Signal { 25 | return mapControlEvents(.valueChanged) { $0.value } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/UIKit/iOS/UISwitch.swift: -------------------------------------------------------------------------------- 1 | import ReactiveSwift 2 | import enum Result.NoError 3 | import UIKit 4 | 5 | extension Reactive where Base: UISwitch { 6 | /// The action to be triggered when the switch is changed. It also controls 7 | /// the enabled state of the switch 8 | public var toggled: CocoaAction? { 9 | get { 10 | return associatedAction.withValue { info in 11 | return info.flatMap { info in 12 | return info.controlEvents == .valueChanged ? info.action : nil 13 | } 14 | } 15 | } 16 | 17 | nonmutating set { 18 | setAction(newValue, for: .valueChanged) 19 | } 20 | } 21 | /// Sets the on-off state of the switch. 22 | public var isOn: BindingTarget { 23 | return makeBindingTarget { $0.isOn = $1 } 24 | } 25 | 26 | /// A signal of on-off states in `Bool` emitted by the switch. 27 | public var isOnValues: Signal { 28 | return mapControlEvents(.valueChanged) { $0.isOn } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/ReactiveCocoa/ReactiveCocoa/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module ReactiveCocoa { 2 | umbrella header "ReactiveCocoa.h" 3 | private header "ObjCRuntimeAliases.h" 4 | 5 | export * 6 | module * { export * } 7 | } 8 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/LICENSE.md: -------------------------------------------------------------------------------- 1 | **Copyright (c) 2012 - 2016, GitHub, Inc.** 2 | **All rights reserved.** 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Bag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bag.swift 3 | // ReactiveSwift 4 | // 5 | // Created by Justin Spahr-Summers on 2014-07-10. 6 | // Copyright (c) 2014 GitHub. All rights reserved. 7 | // 8 | 9 | /// An unordered, non-unique collection of values of type `Element`. 10 | public struct Bag { 11 | /// A uniquely identifying token for removing a value that was inserted into a 12 | /// Bag. 13 | public struct Token { 14 | fileprivate let value: UInt64 15 | } 16 | 17 | fileprivate var elements: ContiguousArray = [] 18 | fileprivate var tokens: ContiguousArray = [] 19 | 20 | private var nextToken: Token = Token(value: 0) 21 | 22 | public init() {} 23 | 24 | /// Insert the given value into `self`, and return a token that can 25 | /// later be passed to `remove(using:)`. 26 | /// 27 | /// - parameters: 28 | /// - value: A value that will be inserted. 29 | @discardableResult 30 | public mutating func insert(_ value: Element) -> Token { 31 | let token = nextToken 32 | 33 | // Practically speaking, this would overflow only if we have 101% uptime and we 34 | // manage to call `insert(_:)` every 1 ns for 500+ years non-stop. 35 | nextToken = Token(value: token.value + 1) 36 | 37 | elements.append(value) 38 | tokens.append(token.value) 39 | 40 | return token 41 | } 42 | 43 | /// Remove a value, given the token returned from `insert()`. 44 | /// 45 | /// - note: If the value has already been removed, nothing happens. 46 | /// 47 | /// - parameters: 48 | /// - token: A token returned from a call to `insert()`. 49 | @discardableResult 50 | public mutating func remove(using token: Token) -> Element? { 51 | for i in elements.indices.reversed() { 52 | if tokens[i] == token.value { 53 | tokens.remove(at: i) 54 | return elements.remove(at: i) 55 | } 56 | } 57 | 58 | return nil 59 | } 60 | } 61 | 62 | extension Bag: RandomAccessCollection { 63 | public var startIndex: Int { 64 | return elements.startIndex 65 | } 66 | 67 | public var endIndex: Int { 68 | return elements.endIndex 69 | } 70 | 71 | public subscript(index: Int) -> Element { 72 | return elements[index] 73 | } 74 | 75 | public func makeIterator() -> Iterator { 76 | return Iterator(elements) 77 | } 78 | 79 | /// An iterator of `Bag`. 80 | public struct Iterator: IteratorProtocol { 81 | private let base: ContiguousArray 82 | private var nextIndex: Int 83 | private let endIndex: Int 84 | 85 | fileprivate init(_ base: ContiguousArray) { 86 | self.base = base 87 | nextIndex = base.startIndex 88 | endIndex = base.endIndex 89 | } 90 | 91 | public mutating func next() -> Element? { 92 | let currentIndex = nextIndex 93 | 94 | if currentIndex < endIndex { 95 | nextIndex = currentIndex + 1 96 | return base[currentIndex] 97 | } 98 | 99 | return nil 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Deprecations+Removals.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Dispatch 3 | import Result 4 | 5 | // MARK: Unavailable methods in ReactiveSwift 3.0. 6 | extension Signal { 7 | @available(*, unavailable, message:"Use the `Signal.init` that accepts a two-argument generator.") 8 | public convenience init(_ generator: (Observer) -> Disposable?) { fatalError() } 9 | } 10 | 11 | extension Lifetime { 12 | @discardableResult 13 | @available(*, unavailable, message:"Use `observeEnded(_:)` with a method reference to `dispose()` instead.") 14 | public func add(_ d: Disposable?) -> Disposable? { fatalError() } 15 | } 16 | 17 | // MARK: Deprecated types 18 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/EventLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventLogger.swift 3 | // ReactiveSwift 4 | // 5 | // Created by Rui Peres on 30/04/2016. 6 | // Copyright © 2016 GitHub. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A namespace for logging event types. 12 | public enum LoggingEvent { 13 | public enum Signal: String { 14 | case value, completed, failed, terminated, disposed, interrupted 15 | 16 | public static let allEvents: Set = [ 17 | .value, .completed, .failed, .terminated, .disposed, .interrupted, 18 | ] 19 | } 20 | 21 | public enum SignalProducer: String { 22 | case starting, started, value, completed, failed, terminated, disposed, interrupted 23 | 24 | public static let allEvents: Set = [ 25 | .starting, .started, .value, .completed, .failed, .terminated, .disposed, .interrupted, 26 | ] 27 | } 28 | } 29 | 30 | public func defaultEventLog(identifier: String, event: String, fileName: String, functionName: String, lineNumber: Int) { 31 | print("[\(identifier)] \(event) fileName: \(fileName), functionName: \(functionName), lineNumber: \(lineNumber)") 32 | } 33 | 34 | /// A type that represents an event logging function. 35 | /// Signature is: 36 | /// - identifier 37 | /// - event 38 | /// - fileName 39 | /// - functionName 40 | /// - lineNumber 41 | public typealias EventLogger = ( 42 | _ identifier: String, 43 | _ event: String, 44 | _ fileName: String, 45 | _ functionName: String, 46 | _ lineNumber: Int 47 | ) -> Void 48 | 49 | extension Signal { 50 | /// Logs all events that the receiver sends. By default, it will print to 51 | /// the standard output. 52 | /// 53 | /// - parameters: 54 | /// - identifier: a string to identify the Signal firing events. 55 | /// - events: Types of events to log. 56 | /// - fileName: Name of the file containing the code which fired the 57 | /// event. 58 | /// - functionName: Function where event was fired. 59 | /// - lineNumber: Line number where event was fired. 60 | /// - logger: Logger that logs the events. 61 | /// 62 | /// - returns: Signal that, when observed, logs the fired events. 63 | public func logEvents(identifier: String = "", events: Set = LoggingEvent.Signal.allEvents, fileName: String = #file, functionName: String = #function, lineNumber: Int = #line, logger: @escaping EventLogger = defaultEventLog) -> Signal { 64 | func log(_ event: LoggingEvent.Signal) -> ((T) -> Void)? { 65 | return event.logIfNeeded(events: events) { event in 66 | logger(identifier, event, fileName, functionName, lineNumber) 67 | } 68 | } 69 | 70 | return self.on( 71 | failed: log(.failed), 72 | completed: log(.completed) as ((()) -> Void)?, 73 | interrupted: log(.interrupted) as ((()) -> Void)?, 74 | terminated: log(.terminated) as ((()) -> Void)?, 75 | disposed: log(.disposed) as ((()) -> Void)?, 76 | value: log(.value) 77 | ) 78 | } 79 | } 80 | 81 | extension SignalProducer { 82 | /// Logs all events that the receiver sends. By default, it will print to 83 | /// the standard output. 84 | /// 85 | /// - parameters: 86 | /// - identifier: a string to identify the SignalProducer firing events. 87 | /// - events: Types of events to log. 88 | /// - fileName: Name of the file containing the code which fired the 89 | /// event. 90 | /// - functionName: Function where event was fired. 91 | /// - lineNumber: Line number where event was fired. 92 | /// - logger: Logger that logs the events. 93 | /// 94 | /// - returns: Signal producer that, when started, logs the fired events. 95 | public func logEvents(identifier: String = "", 96 | events: Set = LoggingEvent.SignalProducer.allEvents, 97 | fileName: String = #file, 98 | functionName: String = #function, 99 | lineNumber: Int = #line, 100 | logger: @escaping EventLogger = defaultEventLog 101 | ) -> SignalProducer { 102 | func log(_ event: LoggingEvent.SignalProducer) -> ((T) -> Void)? { 103 | return event.logIfNeeded(events: events) { event in 104 | logger(identifier, event, fileName, functionName, lineNumber) 105 | } 106 | } 107 | 108 | return self.on( 109 | starting: log(.starting) as ((()) -> Void)?, 110 | started: log(.started) as ((()) -> Void)?, 111 | failed: log(.failed), 112 | completed: log(.completed) as ((()) -> Void)?, 113 | interrupted: log(.interrupted) as ((()) -> Void)?, 114 | terminated: log(.terminated) as ((()) -> Void)?, 115 | disposed: log(.disposed) as ((()) -> Void)?, 116 | value: log(.value) 117 | ) 118 | } 119 | } 120 | 121 | private protocol LoggingEventProtocol: Hashable, RawRepresentable {} 122 | extension LoggingEvent.Signal: LoggingEventProtocol {} 123 | extension LoggingEvent.SignalProducer: LoggingEventProtocol {} 124 | 125 | private extension LoggingEventProtocol { 126 | func logIfNeeded(events: Set, logger: @escaping (String) -> Void) -> ((T) -> Void)? { 127 | guard events.contains(self) else { 128 | return nil 129 | } 130 | 131 | return { value in 132 | if value is Void { 133 | logger("\(self.rawValue)") 134 | } else { 135 | logger("\(self.rawValue) \(value)") 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/FoundationExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FoundationExtensions.swift 3 | // ReactiveSwift 4 | // 5 | // Created by Justin Spahr-Summers on 2014-10-19. 6 | // Copyright (c) 2014 GitHub. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Dispatch 11 | import enum Result.NoError 12 | import struct Result.AnyError 13 | 14 | #if os(Linux) 15 | import let CDispatch.NSEC_PER_USEC 16 | import let CDispatch.NSEC_PER_SEC 17 | #endif 18 | 19 | extension NotificationCenter: ReactiveExtensionsProvider {} 20 | 21 | extension Reactive where Base: NotificationCenter { 22 | /// Returns a Signal to observe posting of the specified notification. 23 | /// 24 | /// - parameters: 25 | /// - name: name of the notification to observe 26 | /// - object: an instance which sends the notifications 27 | /// 28 | /// - returns: A Signal of notifications posted that match the given criteria. 29 | /// 30 | /// - note: The signal does not terminate naturally. Observers must be 31 | /// explicitly disposed to avoid leaks. 32 | public func notifications(forName name: Notification.Name?, object: AnyObject? = nil) -> Signal { 33 | return Signal { [base = self.base] observer, lifetime in 34 | let notificationObserver = base.addObserver(forName: name, object: object, queue: nil) { notification in 35 | observer.send(value: notification) 36 | } 37 | 38 | lifetime.observeEnded { 39 | base.removeObserver(notificationObserver) 40 | } 41 | } 42 | } 43 | } 44 | 45 | private let defaultSessionError = NSError(domain: "org.reactivecocoa.ReactiveSwift.Reactivity.URLSession.dataWithRequest", 46 | code: 1, 47 | userInfo: nil) 48 | 49 | extension URLSession: ReactiveExtensionsProvider {} 50 | 51 | extension Reactive where Base: URLSession { 52 | /// Returns a SignalProducer which performs the work associated with an 53 | /// `NSURLSession` 54 | /// 55 | /// - parameters: 56 | /// - request: A request that will be performed when the producer is 57 | /// started 58 | /// 59 | /// - returns: A producer that will execute the given request once for each 60 | /// invocation of `start()`. 61 | /// 62 | /// - note: This method will not send an error event in the case of a server 63 | /// side error (i.e. when a response with status code other than 64 | /// 200...299 is received). 65 | public func data(with request: URLRequest) -> SignalProducer<(Data, URLResponse), AnyError> { 66 | return SignalProducer { [base = self.base] observer, lifetime in 67 | let task = base.dataTask(with: request) { data, response, error in 68 | if let data = data, let response = response { 69 | observer.send(value: (data, response)) 70 | observer.sendCompleted() 71 | } else { 72 | observer.send(error: AnyError(error ?? defaultSessionError)) 73 | } 74 | } 75 | 76 | lifetime.observeEnded(task.cancel) 77 | task.resume() 78 | } 79 | } 80 | } 81 | 82 | extension Date { 83 | internal func addingTimeInterval(_ interval: DispatchTimeInterval) -> Date { 84 | return addingTimeInterval(interval.timeInterval) 85 | } 86 | } 87 | 88 | extension DispatchTimeInterval { 89 | internal var timeInterval: TimeInterval { 90 | switch self { 91 | case let .seconds(s): 92 | return TimeInterval(s) 93 | case let .milliseconds(ms): 94 | return TimeInterval(TimeInterval(ms) / 1000.0) 95 | case let .microseconds(us): 96 | return TimeInterval(Int64(us)) * TimeInterval(NSEC_PER_USEC) / TimeInterval(NSEC_PER_SEC) 97 | case let .nanoseconds(ns): 98 | return TimeInterval(ns) / TimeInterval(NSEC_PER_SEC) 99 | case .never: 100 | return .infinity 101 | } 102 | } 103 | 104 | // This was added purely so that our test scheduler to "go backwards" in 105 | // time. See `TestScheduler.rewind(by interval: DispatchTimeInterval)`. 106 | internal static prefix func -(lhs: DispatchTimeInterval) -> DispatchTimeInterval { 107 | switch lhs { 108 | case let .seconds(s): 109 | return .seconds(-s) 110 | case let .milliseconds(ms): 111 | return .milliseconds(-ms) 112 | case let .microseconds(us): 113 | return .microseconds(-us) 114 | case let .nanoseconds(ns): 115 | return .nanoseconds(-ns) 116 | case .never: 117 | return .never 118 | } 119 | } 120 | 121 | /// Scales a time interval by the given scalar specified in `rhs`. 122 | /// 123 | /// - returns: Scaled interval in minimal appropriate unit 124 | internal static func *(lhs: DispatchTimeInterval, rhs: Double) -> DispatchTimeInterval { 125 | let seconds = lhs.timeInterval * rhs 126 | var result: DispatchTimeInterval = .never 127 | if let integerTimeInterval = Int(exactly: (seconds * 1000 * 1000 * 1000).rounded()) { 128 | result = .nanoseconds(integerTimeInterval) 129 | } else if let integerTimeInterval = Int(exactly: (seconds * 1000 * 1000).rounded()) { 130 | result = .microseconds(integerTimeInterval) 131 | } else if let integerTimeInterval = Int(exactly: (seconds * 1000).rounded()) { 132 | result = .milliseconds(integerTimeInterval) 133 | } else if let integerTimeInterval = Int(exactly: (seconds).rounded()) { 134 | result = .seconds(integerTimeInterval) 135 | } 136 | return result 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Lifetime.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import enum Result.NoError 3 | 4 | /// Represents the lifetime of an object, and provides a hook to observe when 5 | /// the object deinitializes. 6 | public final class Lifetime { 7 | private let disposables: CompositeDisposable 8 | 9 | /// A signal that sends a `completed` event when the lifetime ends. 10 | /// 11 | /// - note: Consider using `Lifetime.observeEnded` if only a closure observer 12 | /// is to be attached. 13 | public var ended: Signal { 14 | return Signal { observer, lifetime in 15 | lifetime += (disposables += observer.sendCompleted) 16 | } 17 | } 18 | 19 | /// A flag indicating whether the lifetime has ended. 20 | public var hasEnded: Bool { 21 | return disposables.isDisposed 22 | } 23 | 24 | /// Initialize a `Lifetime` object with the supplied composite disposable. 25 | /// 26 | /// - parameters: 27 | /// - signal: The composite disposable. 28 | internal init(_ disposables: CompositeDisposable) { 29 | self.disposables = disposables 30 | } 31 | 32 | /// Initialize a `Lifetime` from a lifetime token, which is expected to be 33 | /// associated with an object. 34 | /// 35 | /// - important: The resulting lifetime object does not retain the lifetime 36 | /// token. 37 | /// 38 | /// - parameters: 39 | /// - token: A lifetime token for detecting the deinitialization of the 40 | /// associated object. 41 | public convenience init(_ token: Token) { 42 | self.init(token.disposables) 43 | } 44 | 45 | /// Observe the termination of `self`. 46 | /// 47 | /// - parameters: 48 | /// - action: The action to be invoked when `self` ends. 49 | /// 50 | /// - returns: A disposable that detaches `action` from the lifetime, or `nil` 51 | /// if `lifetime` has already ended. 52 | @discardableResult 53 | public func observeEnded(_ action: @escaping () -> Void) -> Disposable? { 54 | return disposables += action 55 | } 56 | 57 | /// Add the given disposable as an observer of `self`. 58 | /// 59 | /// - parameters: 60 | /// - disposable: The disposable to be disposed of when `self` ends. 61 | /// 62 | /// - returns: A disposable that detaches `disposable` from the lifetime, or `nil` 63 | /// if `lifetime` has already ended. 64 | @discardableResult 65 | public static func += (lifetime: Lifetime, disposable: Disposable?) -> Disposable? { 66 | guard let dispose = disposable?.dispose else { return nil } 67 | return lifetime.observeEnded(dispose) 68 | } 69 | } 70 | 71 | extension Lifetime { 72 | /// Factory method for creating a `Lifetime` and its associated `Token`. 73 | /// 74 | /// - returns: A `(lifetime, token)` tuple. 75 | public static func make() -> (lifetime: Lifetime, token: Token) { 76 | let token = Token() 77 | return (Lifetime(token), token) 78 | } 79 | 80 | /// A `Lifetime` that has already ended. 81 | public static let empty: Lifetime = { 82 | let disposables = CompositeDisposable() 83 | disposables.dispose() 84 | return Lifetime(disposables) 85 | }() 86 | } 87 | 88 | extension Lifetime { 89 | /// A token object which completes its signal when it deinitializes. 90 | /// 91 | /// It is generally used in conjuncion with `Lifetime` as a private 92 | /// deinitialization trigger. 93 | /// 94 | /// ``` 95 | /// class MyController { 96 | /// private let (lifetime, token) = Lifetime.make() 97 | /// } 98 | /// ``` 99 | public final class Token { 100 | /// A signal that sends a Completed event when the lifetime ends. 101 | fileprivate let disposables: CompositeDisposable 102 | 103 | public init() { 104 | disposables = CompositeDisposable() 105 | } 106 | 107 | deinit { 108 | disposables.dispose() 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Observer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Observer.swift 3 | // ReactiveSwift 4 | // 5 | // Created by Andy Matuschak on 10/2/15. 6 | // Copyright © 2015 GitHub. All rights reserved. 7 | // 8 | 9 | extension Signal { 10 | /// An Observer is a simple wrapper around a function which can receive Events 11 | /// (typically from a Signal). 12 | public final class Observer { 13 | public typealias Action = (Event) -> Void 14 | private let _send: Action 15 | 16 | /// An action that will be performed upon arrival of the event. 17 | @available(*, deprecated: 2.0, renamed:"send(_:)") 18 | public var action: Action { 19 | guard !interruptsOnDeinit && wrapped == nil else { 20 | return { self._send($0) } 21 | } 22 | return _send 23 | } 24 | 25 | /// Whether the observer should send an `interrupted` event as it deinitializes. 26 | private let interruptsOnDeinit: Bool 27 | 28 | /// The target observer of `self`. 29 | private let wrapped: AnyObject? 30 | 31 | /// An initializer that transforms the action of the given observer with the 32 | /// given transform. 33 | /// 34 | /// If the given observer would perform side effect on deinitialization, the 35 | /// created observer would retain it. 36 | /// 37 | /// - parameters: 38 | /// - observer: The observer to transform. 39 | /// - transform: The transform. 40 | /// - disposable: The disposable to be disposed of when the `TransformerCore` 41 | /// yields any terminal event. If `observer` is a `Signal` input 42 | /// observer, this can be omitted. 43 | internal init( 44 | _ observer: Signal.Observer, 45 | _ transform: @escaping Event.Transformation, 46 | _ disposable: Disposable? = nil 47 | ) { 48 | var hasDeliveredTerminalEvent = false 49 | 50 | self._send = transform { event in 51 | if !hasDeliveredTerminalEvent { 52 | observer._send(event) 53 | 54 | if event.isTerminating { 55 | hasDeliveredTerminalEvent = true 56 | disposable?.dispose() 57 | } 58 | } 59 | } 60 | 61 | self.wrapped = observer.interruptsOnDeinit ? observer : nil 62 | self.interruptsOnDeinit = false 63 | } 64 | 65 | /// An initializer that accepts a closure accepting an event for the 66 | /// observer. 67 | /// 68 | /// - parameters: 69 | /// - action: A closure to lift over received event. 70 | /// - interruptsOnDeinit: `true` if the observer should send an `interrupted` 71 | /// event as it deinitializes. `false` otherwise. 72 | internal init(action: @escaping Action, interruptsOnDeinit: Bool) { 73 | self._send = action 74 | self.wrapped = nil 75 | self.interruptsOnDeinit = interruptsOnDeinit 76 | } 77 | 78 | /// An initializer that accepts a closure accepting an event for the 79 | /// observer. 80 | /// 81 | /// - parameters: 82 | /// - action: A closure to lift over received event. 83 | public init(_ action: @escaping Action) { 84 | self._send = action 85 | self.wrapped = nil 86 | self.interruptsOnDeinit = false 87 | } 88 | 89 | /// An initializer that accepts closures for different event types. 90 | /// 91 | /// - parameters: 92 | /// - value: Optional closure executed when a `value` event is observed. 93 | /// - failed: Optional closure that accepts an `Error` parameter when a 94 | /// failed event is observed. 95 | /// - completed: Optional closure executed when a `completed` event is 96 | /// observed. 97 | /// - interruped: Optional closure executed when an `interrupted` event is 98 | /// observed. 99 | public convenience init( 100 | value: ((Value) -> Void)? = nil, 101 | failed: ((Error) -> Void)? = nil, 102 | completed: (() -> Void)? = nil, 103 | interrupted: (() -> Void)? = nil 104 | ) { 105 | self.init { event in 106 | switch event { 107 | case let .value(v): 108 | value?(v) 109 | 110 | case let .failed(error): 111 | failed?(error) 112 | 113 | case .completed: 114 | completed?() 115 | 116 | case .interrupted: 117 | interrupted?() 118 | } 119 | } 120 | } 121 | 122 | internal convenience init(mappingInterruptedToCompleted observer: Signal.Observer) { 123 | self.init { event in 124 | switch event { 125 | case .value, .completed, .failed: 126 | observer.send(event) 127 | case .interrupted: 128 | observer.sendCompleted() 129 | } 130 | } 131 | } 132 | 133 | deinit { 134 | if interruptsOnDeinit { 135 | // Since `Signal` would ensure that only one terminal event would ever be 136 | // sent for any given `Signal`, we do not need to assert any condition 137 | // here. 138 | _send(.interrupted) 139 | } 140 | } 141 | 142 | /// Puts an event into `self`. 143 | public func send(_ event: Event) { 144 | _send(event) 145 | } 146 | 147 | /// Puts a `value` event into `self`. 148 | /// 149 | /// - parameters: 150 | /// - value: A value sent with the `value` event. 151 | public func send(value: Value) { 152 | _send(.value(value)) 153 | } 154 | 155 | /// Puts a failed event into `self`. 156 | /// 157 | /// - parameters: 158 | /// - error: An error object sent with failed event. 159 | public func send(error: Error) { 160 | _send(.failed(error)) 161 | } 162 | 163 | /// Puts a `completed` event into `self`. 164 | public func sendCompleted() { 165 | _send(.completed) 166 | } 167 | 168 | /// Puts an `interrupted` event into `self`. 169 | public func sendInterrupted() { 170 | _send(.interrupted) 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Optional.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Optional.swift 3 | // ReactiveSwift 4 | // 5 | // Created by Neil Pankey on 6/24/15. 6 | // Copyright (c) 2015 GitHub. All rights reserved. 7 | // 8 | 9 | /// An optional protocol for use in type constraints. 10 | public protocol OptionalProtocol { 11 | /// The type contained in the otpional. 12 | associatedtype Wrapped 13 | 14 | init(reconstructing value: Wrapped?) 15 | 16 | /// Extracts an optional from the receiver. 17 | var optional: Wrapped? { get } 18 | } 19 | 20 | extension Optional: OptionalProtocol { 21 | public var optional: Wrapped? { 22 | return self 23 | } 24 | 25 | public init(reconstructing value: Wrapped?) { 26 | self = value 27 | } 28 | } 29 | 30 | extension Signal { 31 | /// Turns each value into an Optional. 32 | internal func optionalize() -> Signal { 33 | return map(Optional.init) 34 | } 35 | } 36 | 37 | extension SignalProducer { 38 | /// Turns each value into an Optional. 39 | internal func optionalize() -> SignalProducer { 40 | return lift { $0.optionalize() } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/Reactive.swift: -------------------------------------------------------------------------------- 1 | /// Describes a provider of reactive extensions. 2 | /// 3 | /// - note: `ReactiveExtensionsProvider` does not indicate whether a type is 4 | /// reactive. It is intended for extensions to types that are not owned 5 | /// by the module in order to avoid name collisions and return type 6 | /// ambiguities. 7 | public protocol ReactiveExtensionsProvider: class {} 8 | 9 | extension ReactiveExtensionsProvider { 10 | /// A proxy which hosts reactive extensions for `self`. 11 | public var reactive: Reactive { 12 | return Reactive(self) 13 | } 14 | 15 | /// A proxy which hosts static reactive extensions for the type of `self`. 16 | public static var reactive: Reactive.Type { 17 | return Reactive.self 18 | } 19 | } 20 | 21 | /// A proxy which hosts reactive extensions of `Base`. 22 | public struct Reactive { 23 | /// The `Base` instance the extensions would be invoked with. 24 | public let base: Base 25 | 26 | /// Construct a proxy 27 | /// 28 | /// - parameters: 29 | /// - base: The object to be proxied. 30 | fileprivate init(_ base: Base) { 31 | self.base = base 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Pods/ReactiveSwift/Sources/ResultExtensions.swift: -------------------------------------------------------------------------------- 1 | import Result 2 | 3 | /// Private alias of the free `materialize()` from `Result`. 4 | /// 5 | /// This exists because within a `Signal` or `SignalProducer` operator, 6 | /// `materialize()` refers to the operator with that name. 7 | /// Namespacing as `Result.materialize()` doesn't work either, 8 | /// because it tries to resolve a static member on the _type_ 9 | /// `Result`, rather than the free function in the _module_ 10 | /// of the same name. 11 | internal func materialize(_ f: () throws -> T) -> Result { 12 | return materialize(try f()) 13 | } 14 | -------------------------------------------------------------------------------- /Pods/Result/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rob Rix 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. -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Info.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 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ProtoKit 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2015 Ritesh Gupta 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | 29 | 30 | ## ReactiveCocoa 31 | 32 | **Copyright (c) 2012 - 2016, GitHub, Inc.** 33 | **All rights reserved.** 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of 36 | this software and associated documentation files (the "Software"), to deal in 37 | the Software without restriction, including without limitation the rights to 38 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 39 | the Software, and to permit persons to whom the Software is furnished to do so, 40 | subject to the following conditions: 41 | 42 | The above copyright notice and this permission notice shall be included in all 43 | copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 47 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 48 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 49 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 50 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 51 | 52 | 53 | ## ReactiveSwift 54 | 55 | **Copyright (c) 2012 - 2016, GitHub, Inc.** 56 | **All rights reserved.** 57 | 58 | Permission is hereby granted, free of charge, to any person obtaining a copy of 59 | this software and associated documentation files (the "Software"), to deal in 60 | the Software without restriction, including without limitation the rights to 61 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 62 | the Software, and to permit persons to whom the Software is furnished to do so, 63 | subject to the following conditions: 64 | 65 | The above copyright notice and this permission notice shall be included in all 66 | copies or substantial portions of the Software. 67 | 68 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 69 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 70 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 71 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 72 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 73 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 74 | 75 | 76 | ## Result 77 | 78 | The MIT License (MIT) 79 | 80 | Copyright (c) 2014 Rob Rix 81 | 82 | Permission is hereby granted, free of charge, to any person obtaining a copy 83 | of this software and associated documentation files (the "Software"), to deal 84 | in the Software without restriction, including without limitation the rights 85 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 86 | copies of the Software, and to permit persons to whom the Software is 87 | furnished to do so, subject to the following conditions: 88 | 89 | The above copyright notice and this permission notice shall be included in all 90 | copies or substantial portions of the Software. 91 | 92 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 93 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 94 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 95 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 96 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 97 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 98 | SOFTWARE. 99 | Generated by CocoaPods - https://cocoapods.org 100 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_RGListKit : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_RGListKit 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/ProtoKit/ProtoKit.framework" 106 | install_framework "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework" 107 | install_framework "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework" 108 | install_framework "${BUILT_PRODUCTS_DIR}/Result/Result.framework" 109 | fi 110 | if [[ "$CONFIGURATION" == "Release" ]]; then 111 | install_framework "${BUILT_PRODUCTS_DIR}/ProtoKit/ProtoKit.framework" 112 | install_framework "${BUILT_PRODUCTS_DIR}/ReactiveCocoa/ReactiveCocoa.framework" 113 | install_framework "${BUILT_PRODUCTS_DIR}/ReactiveSwift/ReactiveSwift.framework" 114 | install_framework "${BUILT_PRODUCTS_DIR}/Result/Result.framework" 115 | fi 116 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 117 | wait 118 | fi 119 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_RGListKitVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_RGListKitVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ProtoKit" "$PODS_CONFIGURATION_BUILD_DIR/ReactiveCocoa" "$PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift" "$PODS_CONFIGURATION_BUILD_DIR/Result" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ProtoKit/ProtoKit.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReactiveCocoa/ReactiveCocoa.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift/ReactiveSwift.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Result/Result.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "ProtoKit" -framework "ReactiveCocoa" -framework "ReactiveSwift" -framework "Result" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_RGListKit { 2 | umbrella header "Pods-RGListKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RGListKit/Pods-RGListKit.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ProtoKit" "$PODS_CONFIGURATION_BUILD_DIR/ReactiveCocoa" "$PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift" "$PODS_CONFIGURATION_BUILD_DIR/Result" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ProtoKit/ProtoKit.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReactiveCocoa/ReactiveCocoa.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift/ReactiveSwift.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/Result/Result.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "ProtoKit" -framework "ReactiveCocoa" -framework "ReactiveSwift" -framework "Result" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/Info.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 | 1.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/ProtoKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ProtoKit : NSObject 3 | @end 4 | @implementation PodsDummy_ProtoKit 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/ProtoKit-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/ProtoKit-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ProtoKitVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ProtoKitVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/ProtoKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module ProtoKit { 2 | umbrella header "ProtoKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ProtoKit/ProtoKit.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ProtoKit 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ProtoKit 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveCocoa/Info.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 | 7.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ReactiveCocoa : NSObject 3 | @end 4 | @implementation PodsDummy_ReactiveCocoa 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.modulemap: -------------------------------------------------------------------------------- 1 | framework module ReactiveCocoa { 2 | umbrella header "ReactiveCocoa.h" 3 | private header "ObjCRuntimeAliases.h" 4 | 5 | export * 6 | module * { export * } 7 | } 8 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveCocoa/ReactiveCocoa.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ReactiveCocoa 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift" "$PODS_CONFIGURATION_BUILD_DIR/Result" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | OTHER_SWIFT_FLAGS[config=Release] = -suppress-warnings 7 | PODS_BUILD_DIR = $BUILD_DIR 8 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReactiveCocoa 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/Info.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.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/ReactiveSwift-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ReactiveSwift : NSObject 3 | @end 4 | @implementation PodsDummy_ReactiveSwift 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/ReactiveSwift-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/ReactiveSwift-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ReactiveSwiftVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ReactiveSwiftVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/ReactiveSwift.modulemap: -------------------------------------------------------------------------------- 1 | framework module ReactiveSwift { 2 | umbrella header "ReactiveSwift-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReactiveSwift/ReactiveSwift.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ReactiveSwift 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Result" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 6 | OTHER_SWIFT_FLAGS[config=Release] = -suppress-warnings 7 | PODS_BUILD_DIR = $BUILD_DIR 8 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReactiveSwift 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Info.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.2.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Result-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Result : NSObject 3 | @end 4 | @implementation PodsDummy_Result 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Result-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Result-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ResultVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ResultVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Result.modulemap: -------------------------------------------------------------------------------- 1 | framework module Result { 2 | umbrella header "Result-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Result/Result.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Result 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Result 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RGListKit 2 | 3 | RGListKit is a **Protocol** & **MVVM** based framework for populating `UITableView` & `UICollectionView`. It takes care of **batch-reload** as well which is powered by [Dwifft](https://github.com/jflinter/Dwifft). 4 | 5 | ## Features 6 | - No need to call `reloadData()` 7 | - No need to manage indexPaths to `performBatchUpdates(_:, completion:)` 8 | - No need to use different apis to populate UITableView & UICollectionView 9 | - It works with multiple sections 10 | - It works with multiple cell types 11 | - `ListableView`, a protocol which unifies UITableView & UICollectionView 12 | - `ListManager` takes care of populating a `ListableView` 13 | - `[sections]` is all you need to set which acts like a datasource to populate a `ListableView` 14 | - `ItemModel`, a protocol which unifies UITableViewCell & UICollectionViewCell 15 | - Every cell is populated/configured via an `ItemModel` which is based on MVVM pattern 16 | - Decoupled diffing algorithm, powered by [Dwifft](https://github.com/jflinter/Dwifft) 17 | - Extendible API 18 | - Written completely in Swift 19 | 20 | ## Installation 21 | 22 | ### Cocoapods 23 | To integrate RGListKit into your Xcode project using CocoaPods, specify it in your Podfile: 24 | 25 | #### Swift 3.1 26 | ``` 27 | pod 'RGListKit', :git => 'https://github.com/riteshhgupta/RGListKit.git', :branch => 'swift3' 28 | ``` 29 | 30 | #### Swift 4.0 31 | ``` 32 | pod 'RGListKit', :git => 'https://github.com/riteshhgupta/RGListKit.git' 33 | ``` 34 | 35 | #### Swift 4.0 + ReactiveSwift 36 | ``` 37 | pod 'RGListKit/ReactiveSwift', :git => 'https://github.com/riteshhgupta/RGListKit.git', :branch => 'swift4' 38 | ``` 39 | 40 | ## Example 41 | ### UITableView 42 | ```swift 43 | ... 44 | let tableView = UITableView() 45 | let cellModels: [ItemModel] = [...] 46 | let sectionModel = SectionModel(id: "section-one-id", cells: cellModels) 47 | 48 | listManager = ListManager(listView: tableView) 49 | listManager.sections = [sectionModel] 50 | ... 51 | ``` 52 | 53 | ### UICollectionView 54 | ```swift 55 | ... 56 | let collectionView = UICollectionView() 57 | let cellModels: [ItemModel] = [...] 58 | let sectionModel = SectionModel(id: "section-one-id", cells: cellModels) 59 | 60 | listManager = ListManager(listView: collectionView) 61 | listManager.sections = [sectionModel] 62 | ... 63 | ``` 64 | 65 | ## Internal Architecture 66 | 67 | - As you can see the api for populating UITableView or UICollectionView is identical, one of the benefits of using RGListKit. 68 | - `ItemModel` defines a cell or even a header/footer-view for both UITableViewCell & UICollectionViewCell 69 | - `ListManager` has a property `sections` which when set triggers the view update 70 | - All the updates are by default batch-update but you can turn it off by setting `shouldPerformBatchUpdate = false` 71 | - You don't have to worry about indexPaths anymore, it uses diffing of old & new array of sections which calculates & performs the update for you. 72 | - It doesn't intefere at all with custom views, like custom table cell or custom layout for collection view. RGListKit only takes care of your datasource and not the UI appearance. So you are free to use any custom layouts as required along with RGListKit. 73 | - Since RGListKit consumes both `delegate` & `datasource` so you can simply extend `ListManager` to handle any custom use cases like `didSelect` when required. All the methods will be available under `ListManager` e.g. 74 | 75 | ```swift 76 | // UICollectionView 77 | 78 | extension ListManager { 79 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 80 | } 81 | } 82 | 83 | ``` 84 | ```swift 85 | // UITableView 86 | 87 | extension ListManager { 88 | public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { 89 | } 90 | } 91 | ``` 92 | 93 | - There are couple of examples in the project itself which you can checkout or create an issue or ping [me](https://twitter.com/_riteshhh) if anything comes up 👍 94 | 95 | ## Blogs/Newsletter 96 | List of online sources which have mentioned RGListKit, 97 | 98 | - [Natasha's Swift newsletter - issue #133](https://swiftnews.curated.co/#libraries) 99 | - [Swift's Weekly - issue #78](http://digest.swiftweekly.com/issues/swift-weekly-issue-78-59042) 100 | - [Compile Swift newsletter - issue #58](http://mailchi.mp/baadd551f100/the-compileswift-newsletter-issue-1481361) 101 | - [iOS Cookies Newsletter - issue #82](http://mailchi.mp/1cfc2545e484/ios-cookies-newsletter-1406733) 102 | 103 | ## Contributing 104 | 105 | Contributions are welcome and encouraged! Open an [issue](https://github.com/riteshhgupta/RGListKit/issues/new) or submit a [pull request](https://github.com/riteshhgupta/swift-snippets/compare) 🚀 106 | 107 | ## Licence 108 | 109 | RGListKit is available under the MIT license. See the LICENSE file for more info. 110 | -------------------------------------------------------------------------------- /RGListKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'RGListKit' 3 | spec.version = '1.0' 4 | spec.summary = 'RGListKit - the missing gap between UITableView & UICollectionView!' 5 | spec.author = { 6 | 'Ritesh Gupta' => 'rg.riteshh@gmail.com' 7 | } 8 | spec.license = 'MIT' 9 | spec.homepage = 'https://github.com/riteshhgupta/RGListKit' 10 | spec.source = { 11 | :git => 'https://github.com/riteshhgupta/RGListKit.git', 12 | :tag => '1.0' 13 | } 14 | spec.ios.deployment_target = "9.0" 15 | spec.requires_arc = true 16 | 17 | spec.subspec 'Core' do |core| 18 | core.dependency 'ProtoKit', '~> 1.2' 19 | core.source_files = 'Source/**/*.swift', 'Source/**/*.xib' 20 | core.exclude_files = 'Source/Reactive/*.swift' 21 | end 22 | 23 | spec.subspec 'ReactiveSwift' do |reactiveswift| 24 | reactiveswift.dependency 'RGListKit/Core' 25 | reactiveswift.dependency 'ReactiveSwift', '~> 3.0' 26 | reactiveswift.dependency 'ReactiveCocoa', '~> 7.0' 27 | reactiveswift.source_files = 'Source/**/*.swift' 28 | end 29 | 30 | spec.default_subspec = 'Core' 31 | 32 | end 33 | -------------------------------------------------------------------------------- /RGListKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RGListKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /RGListKit/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 06/01/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /RGListKit/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /RGListKit/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /RGListKit/CollectionCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionCell.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 01/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ReactiveSwift 12 | import ReactiveCocoa 13 | 14 | struct CollectionCellModel: ListViewItemModel { 15 | var id: String 16 | var title: String 17 | 18 | var reuseIdentifier: String { return "CollectionCell" } 19 | var height: CGFloat { return 64.0 } 20 | var width: CGFloat { return 64.0 } 21 | 22 | init(title: String) { 23 | self.title = title 24 | self.id = title 25 | } 26 | } 27 | 28 | final class CollectionCell: UICollectionViewCell { 29 | 30 | let itemModel = MutableProperty(nil) 31 | 32 | @IBOutlet var titleLabel: UILabel! 33 | 34 | override func awakeFromNib() { 35 | super.awakeFromNib() 36 | titleLabel.reactive.text <~ itemModel 37 | .producer 38 | .skipNil() 39 | .map{ $0 as? CollectionCellModel } 40 | .skipNil() 41 | .map { $0.title } 42 | } 43 | } 44 | 45 | extension CollectionCell: ReactiveListViewItemModelInjectable {} 46 | -------------------------------------------------------------------------------- /RGListKit/CollectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 01/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReactiveSwift 11 | import ReactiveCocoa 12 | 13 | final class CollectionViewController: UIViewController { 14 | 15 | @IBOutlet weak var collectionView: UICollectionView! { 16 | didSet { 17 | listViewHolder = ReactiveDiffableListViewHolder(listView: collectionView, delegate: self) 18 | } 19 | } 20 | 21 | var listViewHolder: ReactiveDiffableListViewHolder! 22 | let items = MutableProperty<[SectionModel]?>(nil) 23 | 24 | override func viewDidAppear(_ animated: Bool) { 25 | super.viewDidAppear(animated) 26 | listViewHolder.reactive.sections <~ items.producer.skipNil() 27 | loadCacheData() 28 | mockAPIData() 29 | } 30 | } 31 | 32 | extension CollectionViewController { 33 | 34 | func loadCacheData() { 35 | let cells = (0..<50).map { "\($0)" }.map { CollectionCellModel(title: $0) } 36 | let section = SectionModel(id: "section-one", cells: cells) 37 | items.value = [section] 38 | } 39 | 40 | func mockAPIData() { 41 | let delay = DispatchTime.now() + 2 42 | DispatchQueue.main.asyncAfter(deadline: delay) { 43 | let cells = (0..<50).filter { $0 % 2 == 0 }.map { "\($0)" }.map { CollectionCellModel(title: $0) } 44 | let section = SectionModel(id: "section-one", cells: cells) 45 | self.items.value = [section] 46 | } 47 | } 48 | } 49 | 50 | extension DiffableListViewHolder { 51 | 52 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 53 | guard let vc = delegate as? CollectionViewController else { return } 54 | print("CollectionViewController didSelectItemAt = \(indexPath.item)") 55 | print(vc.view) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /RGListKit/Info.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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /RGListKit/StackItemView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackItemView.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 09/12/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | import ReactiveSwift 13 | import Result 14 | 15 | struct TitleStackViewItemModel: StackViewItemModel { 16 | 17 | let title: String 18 | var itemType: Nibable.Type { return StackItemView.self } 19 | var height: CGFloat { return 64.0 } 20 | var width: CGFloat { return 100.0 } 21 | } 22 | 23 | final class StackItemView: UIView { 24 | 25 | var itemModel = MutableProperty(nil) 26 | 27 | @IBOutlet var label: UILabel! 28 | 29 | override func awakeFromNib() { 30 | super.awakeFromNib() 31 | label.reactive.text <~ reactive.title 32 | } 33 | } 34 | 35 | extension StackItemView: ReactiveStackViewItemModelInjectable {} 36 | 37 | extension Reactive where Base: StackItemView { 38 | 39 | var title: SignalProducer { 40 | return base 41 | .itemModel 42 | .producer 43 | .skipNil() 44 | .map { $0 as? TitleStackViewItemModel } 45 | .skipNil() 46 | .map { $0.title } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /RGListKit/StackItemView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /RGListKit/StackViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewController.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 09/12/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ReactiveSwift 12 | 13 | class StackViewController: UIViewController { 14 | 15 | @IBOutlet var collectionView: UICollectionView! 16 | @IBOutlet var collectionViewWidthConstraint: NSLayoutConstraint! 17 | 18 | var horizontalStackView: ReactiveStackViewHolder! { 19 | didSet { 20 | horizontalStackView.reactive.itemModels <~ MutableProperty([ 21 | TitleStackViewItemModel(title: "14"), 22 | TitleStackViewItemModel(title: "15"), 23 | TitleStackViewItemModel(title: "16") 24 | ]) 25 | } 26 | } 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | horizontalStackView = ReactiveStackViewHolder( 31 | listView: collectionView, 32 | dynamicConstraint: collectionViewWidthConstraint, 33 | isVertical: false 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RGListKit/TableCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableCell.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 27/12/16. 6 | // Copyright © 2016 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ReactiveSwift 12 | import ReactiveCocoa 13 | import Result 14 | 15 | struct TableCellModel: ListViewItemModel { 16 | var id: String 17 | let title: String 18 | var reuseIdentifier: String { 19 | return "TableCell" 20 | } 21 | var height: CGFloat { 22 | return 64.0 23 | } 24 | init(title: String) { 25 | self.title = title 26 | self.id = title 27 | } 28 | } 29 | 30 | final class TableCell: UITableViewCell { 31 | 32 | let itemModel = MutableProperty(nil) 33 | 34 | @IBOutlet weak var titleLabel: UILabel! 35 | 36 | override func awakeFromNib() { 37 | super.awakeFromNib() 38 | titleLabel.reactive.text <~ reactive.title 39 | } 40 | } 41 | 42 | extension Reactive where Base: TableCell { 43 | 44 | var title: SignalProducer { 45 | return base 46 | .itemModel 47 | .producer 48 | .skipNil() 49 | .map { $0 as? TableCellModel } 50 | .skipNil() 51 | .map { $0.title } 52 | } 53 | } 54 | 55 | extension TableCell: ReactiveListViewItemModelInjectable {} 56 | -------------------------------------------------------------------------------- /RGListKit/TableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 16/12/16. 6 | // Copyright © 2016 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ReactiveSwift 11 | import ReactiveCocoa 12 | 13 | class TableViewController: UIViewController { 14 | 15 | @IBOutlet public var tableView: UITableView! { 16 | didSet { 17 | listViewHolder = ReactiveDiffableListViewHolder(listView: tableView) 18 | } 19 | } 20 | 21 | let items = MutableProperty<[SectionModel]?>(nil) 22 | var listViewHolder: ReactiveDiffableListViewHolder! 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | listViewHolder.reactive.sections <~ items.producer.skipNil() 27 | loadCacheData() 28 | mockAPIData() 29 | } 30 | } 31 | 32 | extension TableViewController { 33 | 34 | func loadCacheData() { 35 | let cells = (0..<10).map { "\($0)" }.map { TableCellModel(title: $0) } 36 | let section = SectionModel(id: "one", cells: cells) 37 | items.value = [section] 38 | } 39 | 40 | func mockAPIData() { 41 | let delay = DispatchTime.now() + 2 42 | DispatchQueue.main.asyncAfter(deadline: delay) { 43 | let cells = (0..<10).filter { $0 % 2 == 0 }.map { "\($0)" }.map { TableCellModel(title: $0) } 44 | let section = SectionModel(id: "one", cells: cells) 45 | self.items.value = [section] 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/DiffKit/RGCollectionViewDiffCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RGCollectionViewDiffCalculator.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 13/05/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | -- `RGCollectionViewDiffCalculator` is an internal class for UICollectionView 13 | which makes RGListKit's design work with Dwiftt's design 14 | 15 | -- its implements `ListableDiffCalculator` protocol which is later used to 16 | perform batch updates 17 | */ 18 | 19 | final class RGCollectionViewDiffCalculator: CollectionViewDiffCalculator {} 20 | 21 | extension RGCollectionViewDiffCalculator: ListableDiffCalculator { 22 | 23 | public func batchReload(_ sections: [SectionModel]) { 24 | self.sectionedValues = SectionedValues( 25 | sections.map({ ($0, $0.cells.map({ $0.model })) }) 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/DiffKit/RGTableViewDiffCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RGTableViewDiffCalculator.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 13/05/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | -- `RGTableViewDiffCalculator` is an internal class for UITableView 13 | which makes RGListKit's design work with Dwiftt's design 14 | 15 | -- its implements `ListableDiffCalculator` protocol which is later used to 16 | perform batch updates 17 | */ 18 | 19 | final class RGTableViewDiffCalculator: TableViewDiffCalculator {} 20 | 21 | extension RGTableViewDiffCalculator: ListableDiffCalculator { 22 | 23 | public func batchReload(_ sections: [SectionModel]) { 24 | self.sectionedValues = SectionedValues( 25 | sections.map({ ($0, $0.cells.map({ $0.model })) }) 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/DiffKit/SectionedValues.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionedValues.swift 3 | // Dwifft 4 | // 5 | // Created by Jack Flintermann on 4/14/17. 6 | // Copyright © 2017 jflinter. All rights reserved. 7 | // 8 | 9 | /// SectionedValues represents, well, a bunch of sections and their associated values. 10 | /// You can think of it sort of like an "ordered dictionary", or an order of key-pairs. 11 | /// If you are diffing a multidimensional structure of values (what might normally be, 12 | /// for example, a 2D array), you will want to use this. 13 | public struct SectionedValues: Equatable { 14 | 15 | /// Initializes the struct with an array of key-pairs. 16 | /// 17 | /// - Parameter sectionsAndValues: An array of tuples. The first element in the tuple is 18 | /// the value of the section. The second element is an array of values to be associated with 19 | /// that section. Ordering matters, obviously. Note, it's totally ok if `sectionsAndValues` 20 | /// contains duplicate sections (or duplicate values within those sections). 21 | public init(_ sectionsAndValues: [(Section, [Value])] = []) { 22 | self.sectionsAndValues = sectionsAndValues 23 | } 24 | 25 | /// The underlying tuples contained in the receiver 26 | public let sectionsAndValues: [(Section, [Value])] 27 | 28 | internal var sections: [Section] { get { return self.sectionsAndValues.map { $0.0 } } } 29 | internal subscript(i: Int) -> (Section, [Value]) { 30 | return self.sectionsAndValues[i] 31 | } 32 | 33 | 34 | /// Returns a new SectionedValues appending a new key-value pair. I think this might be useful 35 | /// if you're building up a SectionedValues conditionally? (Well, I hope it is, anyway.) 36 | /// 37 | /// - Parameter sectionAndValue: the new key-value pair 38 | /// - Returns: a new SectionedValues containing the receiever's contents plus the new pair. 39 | public func appending(sectionAndValue: (Section, [Value])) -> SectionedValues { 40 | return SectionedValues(self.sectionsAndValues + [sectionAndValue]) 41 | } 42 | 43 | /// Compares two `SectionedValues` instances 44 | public static func ==(lhs: SectionedValues, rhs: SectionedValues) -> Bool { 45 | guard lhs.sectionsAndValues.count == rhs.sectionsAndValues.count else { return false } 46 | for i in 0..<(lhs.sectionsAndValues.count) { 47 | let ltuple = lhs.sectionsAndValues[i] 48 | let rtuple = rhs.sectionsAndValues[i] 49 | if (ltuple.0 != rtuple.0 || ltuple.1 != rtuple.1) { 50 | return false 51 | } 52 | } 53 | return true 54 | } 55 | } 56 | 57 | // MARK: - Custom grouping 58 | public extension SectionedValues where Section: Hashable { 59 | 60 | /// This is a convenience initializer of sorts for `SectionedValues`. It acknowledges 61 | /// that sometimes you have an array of things that are naturally "groupable" - maybe 62 | /// a list of names in an address book, that can be grouped into their first initial, 63 | /// or a bunch of events that can be grouped into buckets of timestamps. This will handle 64 | /// clumping all of your values into the correct sections, and ordering everything correctly. 65 | /// 66 | /// - Parameters: 67 | /// - values: All of the values that will end up in the `SectionedValues` you're making. 68 | /// - valueToSection: A function that maps each value to the section it will inhabit. 69 | /// In the above examples, this would take a name and return its first initial, 70 | /// or take an event and return its bucketed timestamp. 71 | /// - sortSections: A function that compares two sections, and returns true if the first 72 | /// should be sorted before the second. Used to sort the sections in the returned `SectionedValues`. 73 | /// - sortValues: A function that compares two values, and returns true if the first 74 | /// should be sorted before the second. Used to sort the values in each section of the returned `SectionedValues`. 75 | public init( 76 | values: [Value], 77 | valueToSection: ((Value) -> Section), 78 | sortSections: ((Section, Section) -> Bool), 79 | sortValues: ((Value, Value) -> Bool)) { 80 | var dictionary = [Section: [Value]]() 81 | for value in values { 82 | let section = valueToSection(value) 83 | var current = dictionary[section] ?? [] 84 | current.append(value) 85 | dictionary[section] = current 86 | } 87 | let sortedSections = dictionary.keys.sorted(by: sortSections) 88 | self.init(sortedSections.map { section in 89 | let values = dictionary[section] ?? [] 90 | let sortedValues = values.sorted(by: sortValues) 91 | return (section, sortedValues) 92 | }) 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Source/ListKit/Core/DiffableListViewHolder+Extension.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // DiffableListViewHolder+Extension.swift 4 | // RGListKit 5 | // 6 | // Created by Ritesh Gupta on 04/10/17. 7 | // Copyright © 2017 Ritesh. All rights reserved. 8 | // 9 | 10 | import Foundation 11 | import UIKit 12 | import ProtoKit 13 | 14 | extension DiffableListViewHolder { 15 | 16 | func itemData(at indexPath: IndexPath) -> (Item, ListViewItemModel) { 17 | let model = sections[indexPath.section].cells[indexPath.row] 18 | let item: Item = listView.reusableItem(withIdentifier: model.reuseIdentifier, for: indexPath) 19 | return (item, model) 20 | } 21 | 22 | func headerFooterItemData(at indexPath: IndexPath, of kind: String) -> (Item, ListViewItemModel)? { 23 | let section = sections[indexPath.section] 24 | let identifier: String 25 | let headerFooterModel: ListViewItemModel 26 | switch kind { 27 | case UICollectionElementKindSectionHeader: 28 | guard let model = section.header else { return nil } 29 | identifier = model.reuseIdentifier 30 | headerFooterModel = model 31 | case UICollectionElementKindSectionFooter: 32 | guard let model = section.footer else { return nil } 33 | identifier = model.reuseIdentifier 34 | headerFooterModel = model 35 | default: 36 | return nil 37 | } 38 | let item: Item? = listView.reusableHeaderFooterItem(withIdentifier: identifier, for: indexPath, of: kind) 39 | guard let view = item else { return nil } 40 | return (view, headerFooterModel) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/ListKit/Core/DiffableListViewHolder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionManager.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 02/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | /* 14 | -- `ListManager` is the only public class which one needs to use to manage 15 | table/collection-views 16 | 17 | -- `listView` could be a table/collection-view 18 | 19 | -- `shouldPerformBatchUpdate` controls whether to do a complete reload or 20 | just update the changes 21 | 22 | -- `sections` is the only public variable one needs to set to update 23 | table/collection-view 24 | */ 25 | 26 | public typealias Closure = ((P) -> (Q)) 27 | 28 | open class DiffableListViewHolder: ListViewHolder { 29 | 30 | let diffCalculator: ListableDiffCalculator 31 | 32 | public weak var delegate: AnyObject? 33 | public var shouldPerformBatchUpdate: Bool 34 | 35 | // datasource 36 | public var sections: [SectionModel] = [] { 37 | didSet { 38 | if shouldPerformBatchUpdate { diffCalculator.batchReload(sections) } 39 | else { listView.reloadItems() } 40 | } 41 | } 42 | 43 | public init(listView: DiffableListView, shouldPerformBatchUpdate: Bool = true, delegate: AnyObject? = nil) { 44 | self.delegate = delegate 45 | self.diffCalculator = listView.diffCalculator 46 | self.shouldPerformBatchUpdate = shouldPerformBatchUpdate 47 | 48 | super.init(listView: listView) 49 | } 50 | 51 | override open func numberOfSectionsIn(listableView: ListableView) -> Int { 52 | return sections.count 53 | } 54 | 55 | override open func listableView(_ listableView: ListableView, numberOfItemsInSection section: Int) -> Int { 56 | return sections[section].cells.count 57 | } 58 | 59 | override open func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item { 60 | let data: (Item, ListViewItemModel) = itemData(at: indexPath) 61 | let (item, model) = data 62 | guard let cell = item as? ListViewItemModelInjectable, let injector = cell.itemModel else { return item } 63 | injector(model) 64 | return item 65 | } 66 | 67 | override open func listableView(_ listableView: ListableView, viewForHeaderFooterAt indexPath: IndexPath, of kind: String) -> Item? { 68 | let data: (Item, ListViewItemModel)? = headerFooterItemData(at: indexPath, of: kind) 69 | guard let (item, model) = data else { return nil } 70 | guard let view = item as? ListViewItemModelInjectable, let injector = view.itemModel else { return item } 71 | injector(model) 72 | return item 73 | } 74 | 75 | override open func listableView(_ listableView: ListableView, sizeForItemAt indexPath: IndexPath) -> CGSize { 76 | return sections[indexPath.section].cells[indexPath.row].size 77 | } 78 | 79 | override open func listableView(_ listableView: ListableView, estimatedHeightForItemAt indexPath: IndexPath) -> CGFloat { 80 | return sections[indexPath.section].cells[indexPath.row].estimatedHeight 81 | } 82 | 83 | override open func listableView(_ listableView: ListableView, heightForHeaderInSection section: Int) -> CGFloat { 84 | return sections[section].header?.height ?? 0.0 85 | } 86 | 87 | override open func listableView(_ listableView: ListableView, heightForFooterInSection section: Int) -> CGFloat { 88 | return sections[section].footer?.height ?? 0.0 89 | } 90 | 91 | override open func listableView(_ listableView: ListableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { 92 | return sections[section].header?.estimatedHeight ?? 0.0 93 | } 94 | 95 | override open func listableView(_ listableView: ListableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { 96 | return sections[section].footer?.estimatedHeight ?? 0.0 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Source/ListKit/Core/EquatableItemModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EquatableListViewItemModel.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 01/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `EquatableListViewItemModel` is an internal struct that gets injected into 14 | dwifft calculator 15 | */ 16 | 17 | struct EquatableListViewItemModel: ListViewItemModel, Equatable { 18 | 19 | var id: String 20 | var reuseIdentifier: String 21 | var height: CGFloat 22 | var width: CGFloat 23 | 24 | init(id: String, reuseIdentifier: String, height: CGFloat, width: CGFloat = 0.0) { 25 | self.id = id 26 | self.reuseIdentifier = reuseIdentifier 27 | self.height = height 28 | self.width = width 29 | } 30 | 31 | public static func ==(lhs: EquatableListViewItemModel, rhs: EquatableListViewItemModel) -> Bool { 32 | return lhs.id == rhs.id 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/ListKit/Core/ListViewItemModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewItemModel.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 04/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | /* 13 | -- `ListViewItemModel` is used to define a cell, header or footer 14 | 15 | -- conform UITableViewCell/UICollectionView or UITableViewHeaderFooterView models to `ListViewItemModel` protocol. 16 | 17 | -- `id` is used to distingiush any 2 cell-model so it should be unique. 18 | 19 | -- return `UITableViewAutomaticDimension` for automatic height calculation or some constant as height. 20 | */ 21 | 22 | public protocol ListViewItemModel { 23 | 24 | var id: String { get } 25 | var width: CGFloat { get } 26 | var height: CGFloat { get } 27 | var estimatedHeight: CGFloat { get } 28 | var reuseIdentifier: String { get } 29 | } 30 | 31 | public extension ListViewItemModel { 32 | 33 | var height: CGFloat { return UITableViewAutomaticDimension } 34 | var width: CGFloat { return 0.0 } 35 | var estimatedHeight: CGFloat { return 100.0 } 36 | 37 | var size: CGSize { return CGSize(width: width, height: height) } 38 | } 39 | 40 | 41 | /* 42 | -- Internal logic 43 | */ 44 | 45 | extension ListViewItemModel { 46 | 47 | var model: EquatableListViewItemModel { 48 | return EquatableListViewItemModel( 49 | id: id, 50 | reuseIdentifier: reuseIdentifier, 51 | height: height, 52 | width: width 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/ListKit/Core/ListViewItemModelInjectable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewItemModelInjectable.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 04/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | -- conform custom UITableViewCell or UICollectionViewCell to `ItemUI` 13 | protocol to make sure that RGListKit calls `configure(withModel:)` method 14 | 15 | -- RGListKit internally calls `configure(withModel:)` inside 16 | `cellForRowAt(:)` (for table) & `cellForItemAt(:)` (for collection-view) 17 | */ 18 | 19 | public protocol ListViewItemModelInjectable { 20 | 21 | var itemModel: ((ListViewItemModel) -> Void)? { get set } 22 | } 23 | -------------------------------------------------------------------------------- /Source/ListKit/Core/ListableDiffCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableDiffCalculator.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 03/05/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | /* 14 | -- `ListableDiffCalculator` is an internal protocol which bridge the gap 15 | between Table/Collection-DiffCalculator 16 | 17 | -- `batchReload(:)` is called to perform batch updates on Table/Collection-View 18 | */ 19 | 20 | public protocol ListableDiffCalculator { 21 | 22 | func batchReload(_ sections: [SectionModel]) 23 | } 24 | 25 | public protocol DiffableListView: ListableView { 26 | 27 | var diffCalculator: ListableDiffCalculator { get } 28 | } 29 | 30 | extension UICollectionView: DiffableListView { 31 | 32 | public var diffCalculator: ListableDiffCalculator { return RGCollectionViewDiffCalculator(collectionView: self) } 33 | } 34 | 35 | extension UITableView: DiffableListView { 36 | 37 | public var diffCalculator: ListableDiffCalculator { return RGTableViewDiffCalculator(tableView: self) } 38 | } 39 | -------------------------------------------------------------------------------- /Source/ListKit/Core/SectionModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionModel.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 04/01/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | -- use `SectionModel` to define a model for a reusable section-view (table or collection) 13 | 14 | -- `id` is used to distinguish any 2 section-model so it should be unique. 15 | 16 | -- cell, header & footer --> all follow the same `ListViewItemModel` protocol since 17 | all are reusable and need the same info while configuring them. 18 | */ 19 | 20 | public struct SectionModel: Equatable { 21 | 22 | public var id: String 23 | public var cells: [ListViewItemModel] 24 | public var header: ListViewItemModel? 25 | public var footer: ListViewItemModel? 26 | 27 | public init(id: String, cells: [ListViewItemModel], header: ListViewItemModel? = nil, footer: ListViewItemModel? = nil) { 28 | self.id = id 29 | self.header = header 30 | self.footer = footer 31 | self.cells = cells 32 | } 33 | 34 | public static func ==(lhs: SectionModel, rhs: SectionModel) -> Bool { 35 | return lhs.id == rhs.id 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/ListKit/Extension/Array+RGListKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Array+RGListKit.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 13/05/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Array { 12 | 13 | mutating func replace(_ handler: Closure, with newElement: Element) { 14 | guard let idx = index(where: handler) else { return } 15 | self[idx] = newElement 16 | } 17 | 18 | func replaced(_ handler: Closure, with newElement: Element) -> [Element] { 19 | var items = self 20 | items.replace(handler, with: newElement) 21 | return items 22 | } 23 | 24 | func appended(with newItems: [Element]) -> [Element] { 25 | var items = self 26 | items.append(contentsOf: newItems) 27 | return items 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/ListKit/Extension/ListableViewDatasource+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListableViewDatasource+Extension.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 13/05/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | -- helper methods which one can use with both UITable/UICollectionView 13 | */ 14 | 15 | public extension DiffableListViewHolder { 16 | 17 | /* returns a section from the list of sections based on a closure that returns a bool */ 18 | 19 | public func section(_ handler: Closure) -> SectionModel? { 20 | return sections.filter(handler).first 21 | } 22 | 23 | /* 24 | - replaces a section with a new section 25 | - `sectionHandler` closure contains the required section that needs to be replaced 26 | - return the new section inside `sectionHandler` closure 27 | */ 28 | public func replace( 29 | section filterHandler: Closure, 30 | with sectionHandler: Closure) 31 | { 32 | guard let oldSection = section(filterHandler) else { return } 33 | let newSection = sectionHandler(oldSection) 34 | guard let idx = sections.index(where: { $0.id == oldSection.id }) else { return } 35 | sections[idx] = newSection 36 | } 37 | 38 | /* 39 | - collapses the required section (removes all the items in the required section) 40 | - returns the items in the section which has been collapsed 41 | */ 42 | public func collapseSection(_ handler: Closure) -> [T] { 43 | var items = [T]() 44 | replace(section: handler) { (section) -> SectionModel in 45 | var newSection = section 46 | items = newSection.cells as! [T] 47 | newSection.cells = [] 48 | return newSection 49 | } 50 | return items 51 | } 52 | 53 | /* 54 | - expands the required section (inserts all the items in the required section) 55 | - new items need to be injected to the function (collapseSection(:) returns the collapsed items) 56 | */ 57 | public func expandSection(_ handler: Closure, withItems items: [ListViewItemModel]) { 58 | replace(section: handler) { (section) -> SectionModel in 59 | var newSection = section 60 | newSection.cells = items 61 | return newSection 62 | } 63 | } 64 | } 65 | 66 | extension SectionModel { 67 | 68 | public func item(_ handler: Closure) -> ListViewItemModel? { 69 | return cells.filter(handler).first 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Source/Reactive/Reactive.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reactive.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 04/10/17. 6 | // Copyright © 2017 Ritesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ReactiveSwift 11 | import ReactiveCocoa 12 | import ProtoKit 13 | 14 | public protocol ReactiveListViewItemModelInjectable { 15 | 16 | var itemModel: MutableProperty { get } 17 | } 18 | 19 | 20 | public protocol ReactiveStackViewItemModelInjectable { 21 | 22 | var itemModel: MutableProperty { get } 23 | } 24 | 25 | public extension Reactive where Base: ReactiveDiffableListViewHolder { 26 | 27 | var sections: BindingTarget<[SectionModel]> { 28 | return makeBindingTarget { $0.sections = $1 } 29 | } 30 | } 31 | 32 | public extension Reactive where Base: ReactiveStackViewHolder { 33 | 34 | var itemModels: BindingTarget<[StackViewItemModel]> { 35 | return makeBindingTarget { $0.itemModels = $1 } 36 | } 37 | } 38 | 39 | open class ReactiveDiffableListViewHolder: DiffableListViewHolder { 40 | 41 | override open func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item { 42 | let data: (Item, ListViewItemModel) = itemData(at: indexPath) 43 | let (item, model) = data 44 | guard let cell = item as? ReactiveListViewItemModelInjectable else { return item } 45 | cell.itemModel.value = model 46 | return item 47 | } 48 | 49 | override open func listableView(_ listableView: ListableView, viewForHeaderFooterAt indexPath: IndexPath, of kind: String) -> Item? { 50 | let data: (Item, ListViewItemModel)? = headerFooterItemData(at: indexPath, of: kind) 51 | guard let (item, model) = data else { return nil } 52 | guard let view = item as? ReactiveListViewItemModelInjectable else { return item } 53 | view.itemModel.value = model 54 | return item 55 | } 56 | } 57 | 58 | open class ReactiveStackViewHolder: StackViewHolder { 59 | 60 | override open func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item { 61 | let model = itemModels[indexPath.row] 62 | let item: Item = listableView.reusableItem(withIdentifier: holderType.typeName, for: indexPath) 63 | guard let holder = item as? StackViewItemHolder else { return item } 64 | let contentView = holder.attach(itemType: model.itemType) 65 | guard let stackItem = contentView as? ReactiveStackViewItemModelInjectable else { return item } 66 | stackItem.itemModel.value = model 67 | return item 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewCollectionViewCell.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 01/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | final class StackViewCollectionViewCell: UICollectionViewCell { 14 | 15 | var item: Nibable? 16 | } 17 | 18 | extension StackViewCollectionViewCell: StackViewItemHolder {} 19 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewHolder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewHolder 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | open class StackViewHolder: ListViewHolder { 14 | 15 | let holderType = StackViewCollectionViewCell.self 16 | let dynamicConstraint: NSLayoutConstraint 17 | let isVertical: Bool 18 | 19 | public init(listView: ListableView, dynamicConstraint: NSLayoutConstraint, isVertical: Bool = true) { 20 | self.dynamicConstraint = dynamicConstraint 21 | self.isVertical = isVertical 22 | super.init(listView: listView) 23 | let bundle = Bundle(for: holderType) 24 | let nib = UINib(nibName: holderType.typeName, bundle: bundle) 25 | listView.registerItem(with: nib, for: holderType.typeName) 26 | } 27 | 28 | public var itemModels: [StackViewItemModel] = [] { 29 | didSet { 30 | dynamicConstraint.constant = dynamicConstraintValue 31 | listView.reloadItems() 32 | } 33 | } 34 | 35 | override open func numberOfSectionsIn(listableView: ListableView) -> Int { 36 | return 1 37 | } 38 | 39 | override open func listableView(_ listableView: ListableView, numberOfItemsInSection section: Int) -> Int { 40 | return itemModels.count 41 | } 42 | 43 | override open func listableView(_ listableView: ListableView, itemForItemAt indexPath: IndexPath) -> Item { 44 | let model = itemModels[indexPath.row] 45 | let item: Item = listableView.reusableItem(withIdentifier: holderType.typeName, for: indexPath) 46 | guard let holder = item as? StackViewItemHolder else { return item } 47 | let contentView = holder.attach(itemType: model.itemType) 48 | guard let stackItem = contentView as? StackViewItemModelInjectable else { return item } 49 | stackItem.itemModel?(model) 50 | return item 51 | } 52 | 53 | override open func listableView(_ listableView: ListableView, estimatedHeightForItemAt indexPath: IndexPath) -> CGFloat { 54 | return itemModels[indexPath.row].estimatedHeight 55 | } 56 | 57 | override open func listableView(_ listableView: ListableView, sizeForItemAt indexPath: IndexPath) -> CGSize { 58 | return itemModels[indexPath.row].size 59 | } 60 | } 61 | 62 | extension StackViewHolder { 63 | 64 | var dynamicConstraintValue: CGFloat { 65 | if isVertical { return itemModels.reduce(0, { $0 + $1.height }) } 66 | else { return itemModels.reduce(0, { $0 + $1.width }) } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewItemHolder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewItemHolder.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | public protocol StackViewItemHolder: ReusableListViewItem { 14 | 15 | var item: Nibable? { get set } 16 | var holderView: UIView { get } 17 | } 18 | 19 | public extension StackViewItemHolder { 20 | 21 | public func attach(itemType: Nibable.Type) -> Nibable { 22 | guard let item = self.item else { 23 | let _item = itemType.instance() 24 | self.item = _item 25 | holderView.attach(subview: _item) 26 | return _item 27 | } 28 | return item 29 | } 30 | } 31 | 32 | public extension StackViewItemHolder where Self: UITableViewCell { 33 | 34 | public var holderView: UIView { return contentView } 35 | } 36 | 37 | public extension StackViewItemHolder where Self: UICollectionViewCell { 38 | 39 | public var holderView: UIView { return contentView } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewItemModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewItemModel.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | public protocol StackViewItemModel: ListViewItemModel { 14 | 15 | var itemType: Nibable.Type { get } 16 | } 17 | 18 | public extension StackViewItemModel { 19 | 20 | public var id: String { return UUID().uuidString } 21 | public var reuseIdentifier: String { return "" } 22 | } 23 | -------------------------------------------------------------------------------- /Source/StackViewKit/StackViewItemProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewItemProvider.swift 3 | // GenericTable 4 | // 5 | // Created by Ritesh Gupta on 03/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ProtoKit 12 | 13 | public protocol StackViewItemModelInjectable: Nibable { 14 | 15 | var itemModel: ((StackViewItemModel) -> Void)? { get set } 16 | } 17 | -------------------------------------------------------------------------------- /Source/StackViewKit/UIView+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.swift 3 | // RGListKit 4 | // 5 | // Created by Ritesh Gupta on 01/12/17. 6 | // Copyright © 2017 Ritesh Gupta. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public extension UIView { 13 | 14 | public func attach(subview view: UIView) { 15 | view.translatesAutoresizingMaskIntoConstraints = false 16 | view.frame = bounds 17 | addSubview(view) 18 | let views = ["view": view] 19 | addConstraints("H".constraints(for: views)) 20 | addConstraints("V".constraints(for: views)) 21 | } 22 | } 23 | 24 | fileprivate extension String { 25 | 26 | // because you can 🙃 27 | func constraints(`for` views: [String: Any]) -> [NSLayoutConstraint] { 28 | return NSLayoutConstraint.constraints(withVisualFormat: "\(self):|[view]|", options: [], metrics: nil, views: views) 29 | } 30 | } 31 | --------------------------------------------------------------------------------