├── .swift-version ├── Images ├── Loader.png ├── EmptyDataView.png ├── PullToRefresh.png └── TableView&Search.png ├── Podfile.lock ├── Pods ├── Manifest.lock ├── Target Support Files │ └── Pods-RSMasterTableViewKitExample │ │ ├── Pods-RSMasterTableViewKitExample-acknowledgements.markdown │ │ ├── Pods-RSMasterTableViewKitExample.modulemap │ │ ├── Pods-RSMasterTableViewKitExample-dummy.m │ │ ├── Pods-RSMasterTableViewKitExample.debug.xcconfig │ │ ├── Pods-RSMasterTableViewKitExample.release.xcconfig │ │ ├── Pods-RSMasterTableViewKitExample-umbrella.h │ │ ├── Info.plist │ │ ├── Pods-RSMasterTableViewKitExample-acknowledgements.plist │ │ ├── Pods-RSMasterTableViewKitExample-resources.sh │ │ └── Pods-RSMasterTableViewKitExample-frameworks.sh └── Pods.xcodeproj │ └── project.pbxproj ├── RSMasterTableViewKitExample ├── RSMasterTableViewKitExample │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── nodata-comments.imageset │ │ │ ├── icons8-picture-512.png │ │ │ ├── icons8-picture-512 copy.png │ │ │ ├── icons8-picture-512 copy 2.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Models │ │ └── Comment.swift │ ├── MyTableViewCell.swift │ ├── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── AppDelegate.swift │ └── DemoViewController.swift └── RSMasterTableViewKitExample.xcodeproj │ └── project.pbxproj ├── RSMasterTableViewKit ├── RSMasterTableViewKit.framework │ ├── Info.plist │ ├── RSMasterTableViewKit │ ├── RSEmptyDataView.nib │ │ ├── runtime.nib │ │ └── objects-11.0+.nib │ ├── Modules │ │ ├── RSMasterTableViewKit.swiftmodule │ │ │ ├── arm.swiftdoc │ │ │ ├── arm64.swiftdoc │ │ │ ├── i386.swiftdoc │ │ │ ├── arm.swiftmodule │ │ │ ├── i386.swiftmodule │ │ │ ├── x86_64.swiftdoc │ │ │ ├── arm64.swiftmodule │ │ │ └── x86_64.swiftmodule │ │ └── module.modulemap │ └── Headers │ │ ├── RSMasterTableViewKit.h │ │ └── RSMasterTableViewKit-Swift.h ├── RSMasterTableViewKit │ ├── Info.plist │ ├── Networking │ │ ├── Response │ │ │ ├── ResponseError.swift │ │ │ └── Response.swift │ │ ├── Request │ │ │ ├── Request.swift │ │ │ ├── DataModelRequest.swift │ │ │ └── JSONRequest.swift │ │ └── NetworkManager.swift │ ├── RSMasterTableViewKit.h │ ├── RSTableView │ │ ├── RSTableViewCell.swift │ │ ├── RSPagination.swift │ │ ├── RSSearchBarDelegate.swift │ │ ├── RSTableViewDataSource.swift │ │ └── RSTableView.swift │ ├── Reachability │ │ ├── ReachabilityManager.swift │ │ └── Reachability.swift │ └── RSEmptyDataSet │ │ ├── RSEmptyDataView.swift │ │ └── RSEmptyDataView.xib └── RSMasterTableViewKit.xcodeproj │ └── project.pbxproj ├── Podfile ├── .gitignore ├── RSMasterTableViewKit.xcworkspace ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── contents.xcworkspacedata ├── LICENSE ├── RSMasterTableViewKit.podspec └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /Images/Loader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/Images/Loader.png -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODFILE CHECKSUM: 0cef49bd5480c0f867062c11a7d575d69297ddec 2 | 3 | COCOAPODS: 1.5.3 4 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODFILE CHECKSUM: 0cef49bd5480c0f867062c11a7d575d69297ddec 2 | 3 | COCOAPODS: 1.5.3 4 | -------------------------------------------------------------------------------- /Images/EmptyDataView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/Images/EmptyDataView.png -------------------------------------------------------------------------------- /Images/PullToRefresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/Images/PullToRefresh.png -------------------------------------------------------------------------------- /Images/TableView&Search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/Images/TableView&Search.png -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Info.plist -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/RSMasterTableViewKit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/RSMasterTableViewKit -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/RSEmptyDataView.nib/runtime.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/RSEmptyDataView.nib/runtime.nib -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/RSEmptyDataView.nib/objects-11.0+.nib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/RSEmptyDataView.nib/objects-11.0+.nib -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | workspace 'RSMasterTableViewKit' 2 | xcodeproj 'RSMasterTableViewKitExample/RSMasterTableViewKitExample.xcodeproj' 3 | platform :ios, '10.0' 4 | 5 | target 'RSMasterTableViewKitExample' do 6 | use_frameworks! 7 | 8 | 9 | end 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_RSMasterTableViewKitExample { 2 | umbrella header "Pods-RSMasterTableViewKitExample-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm.swiftdoc -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm64.swiftdoc -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/i386.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/i386.swiftdoc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | RSMasterTableViewKitExample/RSMasterTableViewKitExample.xcodeproj/xcuserdata/rushisangani.xcuserdatad/xcschemes/xcschememanagement.plist 3 | 4 | RSMasterTableViewKit/RSMasterTableViewKit.xcodeproj/xcuserdata/rushisangani.xcuserdatad/xcschemes/xcschememanagement.plist 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_RSMasterTableViewKitExample : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_RSMasterTableViewKitExample 5 | @end 6 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm.swiftmodule -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/i386.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/i386.swiftmodule -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/x86_64.swiftdoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/x86_64.swiftdoc -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/arm64.swiftmodule -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/x86_64.swiftmodule: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/RSMasterTableViewKit.swiftmodule/x86_64.swiftmodule -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512.png -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512 copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512 copy.png -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512 copy 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/HEAD/RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/icons8-picture-512 copy 2.png -------------------------------------------------------------------------------- /RSMasterTableViewKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Modules/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module RSMasterTableViewKit { 2 | umbrella header "RSMasterTableViewKit.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module RSMasterTableViewKit.Swift { 9 | header "RSMasterTableViewKit-Swift.h" 10 | requires objc 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.. 6 | PODS_ROOT = ${SRCROOT}/../Pods 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.. 6 | PODS_ROOT = ${SRCROOT}/../Pods 7 | -------------------------------------------------------------------------------- /RSMasterTableViewKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-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_RSMasterTableViewKitExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_RSMasterTableViewKitExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Models/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // RSMasterTableViewKitExample 4 | // 5 | // Created by Rushi Sangani on 09/06/18. 6 | // Copyright © 2018 Rushi Sangani. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Comment Model 12 | struct Comment: Codable { 13 | 14 | // MARK: - Properties 15 | 16 | var postId: UInt = 0 17 | var id: Int = 0 18 | var name: String = "" 19 | var email: String = "" 20 | var body: String = "" 21 | } 22 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Assets.xcassets/nodata-comments.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icons8-picture-512 copy.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icons8-picture-512 copy 2.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icons8-picture-512.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | }, 23 | "properties" : { 24 | "template-rendering-intent" : "template" 25 | } 26 | } -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/MyTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyTableViewCell.swift 3 | // RSMasterTableViewKitExample 4 | // 5 | // Created by Rushi Sangani on 17/03/18. 6 | // Copyright © 2018 Rushi Sangani. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RSMasterTableViewKit 11 | 12 | class MyTableViewCell: RSTableViewCell { 13 | 14 | // MARK: - Outlets 15 | @IBOutlet weak var titleLabel: UILabel! 16 | 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | } 20 | 21 | override func setSelected(_ selected: Bool, animated: Bool) { 22 | super.setSelected(selected, animated: animated) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Headers/RSMasterTableViewKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSMasterTableViewKit.h 3 | // RSMasterTableViewKit 4 | // 5 | // Created by Rushi Sangani on 10/03/18. 6 | // Copyright © 2018 Rushi Sangani. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for RSMasterTableViewKit. 12 | FOUNDATION_EXPORT double RSMasterTableViewKitVersionNumber; 13 | 14 | //! Project version string for RSMasterTableViewKit. 15 | FOUNDATION_EXPORT const unsigned char RSMasterTableViewKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/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-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Rushi Sangani 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 | -------------------------------------------------------------------------------- /RSMasterTableViewKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "RSMasterTableViewKit" 4 | s.version = "1.2" 5 | s.summary = "A comprehensive UITableView which handles everything that you need." 6 | 7 | s.description = <<-DESC 8 | All-In-One UITableView Kit with inbuilt PullToRefresh, Pagination, EmptyDataSet, Indicator, Networking and much more.. 9 | DESC 10 | 11 | s.homepage = "https://github.com/rushisangani/RSMasterTableViewKit" 12 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 13 | 14 | 15 | s.license = "MIT" 16 | s.license = { :type => "MIT", :file => "LICENSE" } 17 | 18 | s.author = { "Rushi Sangani" => "rushisangani@gmail.com" } 19 | s.social_media_url = "https://github.com/rushisangani" 20 | 21 | 22 | s.platform = :ios, "10.0" 23 | 24 | s.source = { :git => "https://github.com/rushisangani/RSMasterTableViewKit.git", :tag => s.version } 25 | 26 | 27 | s.source_files = "RSMasterTableViewKit", "RSMasterTableViewKit/**/*.{swift}" 28 | s.resources = "RSMasterTableViewKit/**/*.{xib}" 29 | 30 | s.requires_arc = true 31 | s.swift_version = "4.0" 32 | s.pod_target_xcconfig = { "SWIFT_VERSION" => "4" } 33 | 34 | end 35 | 36 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/Response/ResponseError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseError.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Response Error 29 | public struct ResponseError: Error { 30 | let code: Int 31 | let message: String 32 | } 33 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/Response/Response.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResponseType.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Types of Response 29 | //public enum ResponseType { 30 | // case json, model 31 | //} 32 | 33 | /// JSON Response 34 | public typealias JSONResponse = ((Any) -> ()) 35 | 36 | /// Model Response 37 | public typealias DataModelResponse = ((T) -> ()) 38 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSMasterTableViewKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSMasterTableViewKit.h 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | #import 27 | 28 | //! Project version number for RSMasterTableViewKit. 29 | FOUNDATION_EXPORT double RSMasterTableViewKitVersionNumber; 30 | 31 | //! Project version string for RSMasterTableViewKit. 32 | FOUNDATION_EXPORT const unsigned char RSMasterTableViewKitVersionString[]; 33 | 34 | // In this header, you should import all the public headers of your framework using statements like #import 35 | 36 | 37 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/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 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/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 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSTableView/RSTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSReusableTableViewCell.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import UIKit 27 | 28 | /// UITableViewCellConfiguration 29 | public typealias UITableViewCellConfiguration = ((_ cell: UITableViewCell, _ dataObject: T, _ indexPath: IndexPath) -> ()) 30 | 31 | /// Reusable TableViewCell 32 | public protocol Reusable: class { 33 | static var reuseIdentifier: String { get } 34 | } 35 | 36 | /// Classname as cell identifier 37 | extension Reusable { 38 | public static var reuseIdentifier: String { return String(describing: self) } 39 | } 40 | 41 | /// RSTableViewCell 42 | open class RSTableViewCell: UITableViewCell, Reusable { } 43 | 44 | /// UITableView Deque Cell 45 | extension UITableView { 46 | 47 | /// Deque reusable cell with default identifier at indexPath 48 | public func dequeueReusableCell(at indexPath: IndexPath) -> T { 49 | return self.dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as! T 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // RSMasterTableViewKitExample 4 | // 5 | // Created by Rushi Sangani on 10/03/18. 6 | // Copyright © 2018 Rushi Sangani. 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: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | return true 18 | } 19 | 20 | func applicationWillResignActive(_ application: UIApplication) { 21 | // 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. 22 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 23 | } 24 | 25 | func applicationDidEnterBackground(_ application: UIApplication) { 26 | // 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. 27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 28 | } 29 | 30 | func applicationWillEnterForeground(_ application: UIApplication) { 31 | // 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. 32 | } 33 | 34 | func applicationDidBecomeActive(_ application: UIApplication) { 35 | // 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. 36 | } 37 | 38 | func applicationWillTerminate(_ application: UIApplication) { 39 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 40 | } 41 | 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSTableView/RSPagination.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSPagination.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Pagination request status 29 | public enum PageRequestStatus { 30 | case none, started 31 | } 32 | 33 | /// PullToRefresh 34 | public typealias PullToRefreshHandler = () -> () 35 | 36 | /// Pagination 37 | public typealias PaginationHandler = (_ page: UInt) -> () 38 | 39 | /// Constants 40 | let kDefaultStartPage = UInt(0) 41 | let kDefaultPageSize = UInt(20) 42 | 43 | /// Pagination Parameters to fetch page wise data from server 44 | public struct PaginationParameters { 45 | 46 | // MARK: - Properties 47 | 48 | /// Indicates starting page, default is 0 49 | public var startPage: UInt = kDefaultStartPage 50 | 51 | /// Number of records to fetch per page, default is 20 52 | public var size: UInt = kDefaultPageSize 53 | 54 | /// Indicates current page 55 | public var currentPage: UInt = kDefaultStartPage 56 | 57 | // MARK: - Init 58 | public init() {} 59 | 60 | /// Init with values 61 | public init(page: UInt, size: UInt) { 62 | 63 | self.startPage = page 64 | self.currentPage = page 65 | self.size = size 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/Request/Request.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Request.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Request 29 | public protocol Request { 30 | 31 | /// Response Type 32 | associatedtype ResponseType 33 | 34 | /// URL - Specify url string 35 | var url: String { get set } 36 | 37 | /// HTTP Method 38 | var method: HTTPMethod { get set } 39 | 40 | /// Requst Headers 41 | var headers: [String: String]? { get set } 42 | 43 | /// Request Parameters 44 | var parameters: [String: Any]? { get set } 45 | 46 | /// Response Keypath - path to the key in json for result i.e. "response/data/", "data" 47 | var responeKeyPath: String? { get set } 48 | 49 | 50 | //MARK: - Init 51 | 52 | init(url: String) 53 | init(url: String, responeKeyPath: String) 54 | init(url: String, method: HTTPMethod, headers: [String: String]?, parameters: [String: Any]?, responeKeyPath: String?) 55 | 56 | /// execute request 57 | func execute(completion: Result) 58 | } 59 | 60 | extension Request { 61 | 62 | init(url: String) { 63 | 64 | } 65 | 66 | init(url: String, responeKeyPath: String?) { 67 | 68 | } 69 | 70 | init(url: String, method: HTTPMethod, headers: [String: String]?, parameters: [String: Any]?, responeKeyPath: String?) { 71 | 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/Request/DataModelRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModelRequest.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// DataModelRequest 29 | public class DataModelRequest: Request { 30 | 31 | /// Execute request 32 | public func execute(success: @escaping DataModelResponse, failure: ((ResponseError) -> ())? = nil) { 33 | 34 | NetworkManager.shared.execute(request: self, responseType: .dataModel, success: { [weak self] (response) in 35 | 36 | // convert to models 37 | if let data = (response as? Data) { 38 | self?.convertDataToObjects(data, success: success, failure: failure) 39 | } 40 | 41 | }, failure: failure) 42 | } 43 | } 44 | 45 | // MARK: - Private 46 | extension DataModelRequest { 47 | 48 | /// Convert data to specified objects 49 | private func convertDataToObjects(_ data: Data, success: @escaping ((T) -> ()), failure: ((ResponseError) -> ())?) { 50 | 51 | // convert to specified type 52 | let result = try? JSONDecoder().decode(T.self, from: data) 53 | 54 | DispatchQueue.main.async { 55 | 56 | // success 57 | if let result = result { 58 | success(result) 59 | } 60 | 61 | // error 62 | else if let failure = failure { 63 | failure(ResponseError(kModelConversionErrCode, mErrorInModelConversion)) 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSTableView/RSSearchBarDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSSearchBarDelegate.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | 27 | import Foundation 28 | import UIKit 29 | 30 | /// Default PlaceHolder 31 | public let mDefaultSearchPlaceHolder = "Search" 32 | 33 | /// RSSearchBarDelegate 34 | open class RSSearchBarDelegate: NSObject { 35 | 36 | // MARK: - Properties 37 | public var searchBar: UISearchBar? 38 | 39 | /// No result message 40 | var noResultMessage: NSAttributedString? 41 | 42 | /// to execute on search event 43 | private var didSearch: ((String) -> ())? 44 | 45 | // MARK: - Initialize 46 | init(placeHolder: String, message: NSAttributedString?, handler: @escaping ((String) -> ())) { 47 | super.init() 48 | 49 | searchBar = UISearchBar() 50 | searchBar?.searchBarStyle = .minimal 51 | searchBar?.delegate = self 52 | searchBar?.sizeToFit() 53 | searchBar?.placeholder = placeHolder 54 | searchBar?.enablesReturnKeyAutomatically = false 55 | self.noResultMessage = message 56 | self.didSearch = handler 57 | } 58 | 59 | // MARK: - Private 60 | private func searchForText(text: String?) { 61 | guard let handler = didSearch else { return } 62 | handler(text ?? "") 63 | } 64 | } 65 | 66 | 67 | // MARK:- UISearchBarDelegate 68 | extension RSSearchBarDelegate: UISearchBarDelegate { 69 | 70 | public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 71 | searchBar.resignFirstResponder() 72 | } 73 | 74 | public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { 75 | searchForText(text: searchText) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Reachability/ReachabilityManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReachabilityManager.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// Reachability Notification 29 | public let reachabilityChangedNotification = "reachabilityChangedNotification" 30 | 31 | /// Reachability Status 32 | public let reachabilityStatus = "reachabilityStatus" 33 | 34 | /// ReachabilityManager 35 | open class ReachabilityManager { 36 | 37 | // MARK: - Singleton 38 | public static let shared = ReachabilityManager() 39 | 40 | // MARK: - Properties 41 | 42 | /// Reachability Instance 43 | public let reachability = Reachability()! 44 | 45 | /// Reachability Flag 46 | public static var isReachable: Bool { 47 | return ReachabilityManager.shared.connected 48 | } 49 | 50 | /// Checks if connected to network 51 | private var connected: Bool = true { 52 | didSet { 53 | let notification = Notification.init(name: Notification.Name.init(reachabilityChangedNotification), object: self, userInfo: [reachabilityStatus: connected]) 54 | NotificationCenter.default.post(notification) 55 | } 56 | } 57 | 58 | // MARK: - Init 59 | private init() {} 60 | 61 | // MARK: - Initialize 62 | func initialize() { 63 | 64 | // when reachable 65 | reachability.whenReachable = { [weak self] status in 66 | self?.connected = true 67 | } 68 | 69 | // when unreachable 70 | reachability.whenUnreachable = { [weak self] status in 71 | self?.connected = false 72 | } 73 | 74 | // start 75 | try? reachability.startNotifier() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/Request/JSONRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONRequest.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// JSONRequest 29 | public class JSONRequest: Request { 30 | 31 | //MARK: - Request 32 | public typealias ResponseType = Any 33 | 34 | /// URL - Specify url string 35 | public var url: String 36 | 37 | /// HTTP Method 38 | public var method: HTTPMethod = .GET 39 | 40 | /// Requst Headers 41 | public var headers: [String: String]? 42 | 43 | /// Request Parameters 44 | public var parameters: [String: Any]? 45 | 46 | /// Response Keypath - path to the key in json for result i.e. "response/data/", "data" 47 | public var responeKeyPath: String? 48 | 49 | //MARK: - Init 50 | 51 | public init(url: String, method: HTTPMethod, headers: [String: String]? = nil, parameters: [String: Any]? = nil, responeKeyPath: String? = nil) { 52 | self.method = method 53 | self.url = url 54 | self.headers = headers 55 | self.parameters = parameters 56 | self.responeKeyPath = responeKeyPath 57 | } 58 | 59 | public convenience init(url: String, responeKeyPath: String) { 60 | self.init(url: url, method: .GET, responeKeyPath: responeKeyPath) 61 | } 62 | 63 | public convenience init(url: String) { 64 | self.init(url: url, method: .GET) 65 | } 66 | 67 | /// Execute JSON Request 68 | public func execute(completion: Result) { 69 | 70 | } 71 | 72 | public func execute(success: @escaping JSONResponse, failure: ((ResponseError) -> ())? = nil) { 73 | NetworkManager.shared.execute(request: self, responseType: .json, success: success, failure: failure) 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/DemoViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoViewController.swift 3 | // RSMasterTableViewKitExample 4 | // 5 | // Created by Rushi Sangani on 10/03/18. 6 | // Copyright © 2018 Rushi Sangani. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RSMasterTableViewKit 11 | 12 | /// Constants 13 | let kServerURL = "https://jsonplaceholder.typicode.com/comments" 14 | let kPaginationStartPage = UInt(1) 15 | let kPaginationSize = UInt(100) 16 | 17 | class DemoViewController: UIViewController { 18 | 19 | // MARK: - Outlets 20 | @IBOutlet weak var tableView: RSTableView! 21 | 22 | // MARK: - Properties 23 | var dataSource: RSTableViewDataSource? 24 | 25 | // MARK: - Life Cycle 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | 29 | // setup tableview 30 | setupTableView() 31 | } 32 | 33 | override func viewWillAppear(_ animated: Bool) { 34 | super.viewWillAppear(animated) 35 | 36 | // fetch data 37 | fetchInitialData() 38 | } 39 | 40 | /// Fetch initial data 41 | func fetchInitialData() { 42 | 43 | // show indicator 44 | tableView.showIndicator(title: NSAttributedString(string: "LOADING"), tintColor: UIColor.black) 45 | 46 | // fetch and display data 47 | let url = getURLForPage(kPaginationStartPage) 48 | 49 | self.fetchDataFromServer(url: url) { [weak self] (commentList) in 50 | self?.dataSource?.setData(data: commentList) 51 | } 52 | } 53 | 54 | // MARK: - TableView Setup 55 | func setupTableView() { 56 | 57 | // setup tableview and data source 58 | dataSource = RSTableViewDataSource(tableView: tableView, identifier: "cell") { (cell, comment, indexPath) in 59 | 60 | cell.textLabel?.text = "\(indexPath.row+1). \(comment.email)" 61 | cell.detailTextLabel?.text = comment.body 62 | } 63 | 64 | // show empty data view when no data available 65 | tableView.setEmptyDataView(title: NSAttributedString(string: "NO COMMENTS AVAILABLE"), description: NSAttributedString(string: "Comments that you've posted will appear here."), image: UIImage(named: "nodata-comments"), background: nil) 66 | 67 | // search bar 68 | tableView.addSearchBar(noResultMessage: NSAttributedString(string: "No result matching your search criteria")) 69 | dataSource?.searchResultHandler = { [weak self] (searchString, dataArray) in 70 | 71 | // filter 72 | let result = dataArray.filter({ $0.email.starts(with: searchString) }) 73 | self?.dataSource?.setSearchResultData(result, replace: false) 74 | } 75 | 76 | // add pull to refresh 77 | tableView.addPullToRefresh { [weak self] in 78 | DispatchQueue.global().asyncAfter(deadline: .now()+2, execute: { 79 | self?.dataSource?.setData(data: []) 80 | }) 81 | } 82 | 83 | // pull to refresh tint color and text 84 | tableView.setPullToRefresh(tintColor: UIColor.darkGray, attributedText: NSAttributedString(string: "Fetching data")) 85 | 86 | let paginationParams = PaginationParameters(page: 1, size: 50) 87 | 88 | // Pagination 89 | tableView.addPagination(parameters: paginationParams) { [weak self] (page) in 90 | 91 | // url for next page 92 | let url = self?.getURLForPage(page) 93 | 94 | // fetch & append data 95 | self?.fetchDataFromServer(url: url!, completion: { (list) in 96 | self?.dataSource?.appendData(data: list) 97 | }) 98 | } 99 | } 100 | 101 | /// get url 102 | func getURLForPage(_ page: UInt) -> String { 103 | return "\(kServerURL)?_page=\(page)&_limit=\(tableView.paginationParameters?.size ?? kPaginationSize)" 104 | } 105 | 106 | /// fetch data from server 107 | func fetchDataFromServer(url: String, completion: @escaping ([Comment]) -> ()) { 108 | 109 | // request 110 | let request = DataModelRequest<[Comment]>(url: url) 111 | 112 | // execute 113 | request.execute(success: { [weak self] (comments) in 114 | self?.dataSource?.appendData(data: comments) 115 | 116 | }) { [weak self] (error) in 117 | print(error.message) 118 | self?.tableView.hideAllAnimations() 119 | } 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSEmptyDataSet/RSEmptyDataView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSEmptyDataView.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import UIKit 27 | 28 | /// RSEmptyDataBackground 29 | public enum RSEmptyDataBackground { 30 | case color(color: UIColor) 31 | case view(view: UIView) 32 | } 33 | 34 | /// RSEmptyDataView 35 | open class RSEmptyDataView: UIView { 36 | 37 | // MARK: - Outlets 38 | 39 | @IBOutlet weak var backgroundView: UIView! 40 | @IBOutlet weak var parentStackView: UIStackView! 41 | @IBOutlet weak var imageView: UIImageView! 42 | @IBOutlet weak var titleLabel: UILabel! 43 | @IBOutlet weak var descriptionLabel: UILabel! 44 | 45 | // activity indicator 46 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView! 47 | @IBOutlet weak var indicatorLabel: UILabel! 48 | @IBOutlet weak var indicatorStackView: UIStackView! 49 | 50 | // MARK: - Life Cycle 51 | open override func awakeFromNib() { 52 | super.awakeFromNib() 53 | activityIndicator.stopAnimating() 54 | indicatorLabel.isHidden = true 55 | parentStackView.isHidden = true 56 | } 57 | 58 | // MARK: - Public 59 | 60 | /// set empty dataview title, description and image 61 | func setEmptyDataView(title: NSAttributedString?, description: NSAttributedString?, image: UIImage?, background: RSEmptyDataBackground?) { 62 | 63 | // title 64 | if let titleText = title { 65 | titleLabel.attributedText = titleText 66 | }else { 67 | titleLabel.isHidden = true 68 | } 69 | 70 | // description 71 | if let descText = description { 72 | descriptionLabel.attributedText = descText 73 | }else { 74 | descriptionLabel.isHidden = true 75 | } 76 | 77 | // image 78 | if let iconImage = image { 79 | imageView.image = iconImage 80 | }else { 81 | imageView.isHidden = true 82 | } 83 | 84 | // background 85 | if let background = background { 86 | switch background { 87 | case .color(let color): 88 | backgroundView.backgroundColor = color 89 | case .view(let view): 90 | view.frame = backgroundView.bounds 91 | backgroundView.addSubview(view) 92 | backgroundView.sendSubviewToBack(view) 93 | } 94 | } 95 | } 96 | 97 | /// Show loading indicator 98 | func showLoadingIndicator(title: NSAttributedString? = nil, tintColor: UIColor? = nil) { 99 | self.showEmptyDataState(false) 100 | 101 | // loading indicator 102 | if let color = tintColor { 103 | activityIndicator.tintColor = color 104 | } 105 | activityIndicator.startAnimating() 106 | 107 | // text 108 | indicatorLabel.isHidden = false 109 | indicatorLabel.attributedText = title 110 | } 111 | 112 | /// Hide loading indicator 113 | func hideLoadingIndicator() { 114 | activityIndicator.stopAnimating() 115 | } 116 | 117 | /// Hide no search result 118 | func hideNoSearchLabel() { 119 | indicatorLabel.isHidden = true 120 | } 121 | 122 | /// Show empty data state 123 | func showEmptyDataState(_ state: Bool) { 124 | self.parentStackView.isHidden = !state 125 | self.backgroundView.isHidden = self.parentStackView.isHidden 126 | if state { 127 | self.hideLoadingIndicator() 128 | self.hideNoSearchLabel() 129 | } 130 | } 131 | 132 | /// Show No Search Result message 133 | func showNoSearchResultMessage(_ message: NSAttributedString? = nil) { 134 | self.showEmptyDataState(false) 135 | indicatorLabel.isHidden = false 136 | indicatorLabel.attributedText = message 137 | } 138 | } 139 | 140 | // MARK: - View From Nib 141 | public extension UIView { 142 | 143 | /// Load view from nib 144 | class func loadFromNib() -> T { 145 | 146 | let nib = UINib(nibName: String(describing: T.self), bundle: Bundle(for: T.self)) 147 | return nib.instantiate(withOwner: nil, options: nil).first as! T 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RSMasterTableViewKit 2 | 3 | ### Why to use RSMasterTableViewKit? 4 | UITableview is the most used UIKit control for all iOS applications. Simply using UITableview does not complete the functionality of any screen. 5 | Based on the functionality, a developer also need to code for implementing PullToRefresh, SearchBar, Pagination, Showing loading indicator, Empty data set and many more other complex scenarios. As a developer aren't you tired doing this for all your applications by repeating code everytime? 6 | 7 | **RSMasterTableViewKit is built to help developers to quickly integrate UITableView with customization they want with minimal coding effort.** 8 | 9 | ## Features 10 | - Easy to use datasource implementation (No need to write **cellForRowAtIndexPath**) 11 | - PullToRefresh 12 | - Pagination 13 | - SearchBar (Local & Web Search) 14 | - EmptyDataSet 15 | - Loading Indicator with title 16 | - JSON to Codable conversion 17 | - Networking (WebAPI request: GET, POST etc) 18 | - Network Reachabilty Check 19 | 20 | ![Alt text](https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/master/Images/Loader.png "Loader") 21 | ![Alt text](https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/master/Images/TableView&Search.png "TableView") 22 | ![Alt text](https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/master/Images/EmptyDataView.png "EmptyDataView") 23 | ![Alt text](https://raw.githubusercontent.com/rushisangani/RSMasterTableViewKit/master/Images/PullToRefresh.png "PullToRefresh") 24 | 25 | ## Requirements 26 | ```swift 27 | iOS 10.0+ | Xcode 8.3+ | Swift 4.0+ 28 | ``` 29 | 30 | ## Installation 31 | 32 | ### CocoaPods 33 | ```ruby 34 | pod 'RSMasterTableViewKit' or pod 'RSMasterTableViewKit', '~> 1.2' 35 | ``` 36 | ## Usage 37 | 38 | ### Generic DataSource 39 | ```swift 40 | // connect UITableview outlet from storyboard 41 | @IBOutlet weak var tableView: RSTableView! 42 | 43 | // declare a dataSource 44 | var dataSource: RSTableViewDataSource? //here Comment is the datamodel 45 | 46 | // setup tableview 47 | dataSource = RSTableViewDataSource(tableView: tableView, identifier: "cell") { (cell, comment, indexPath) in 48 | 49 | cell.textLabel?.text = "\(indexPath.row+1). \(comment.email)" 50 | cell.detailTextLabel?.text = comment.body 51 | } 52 | ``` 53 | 54 | ### Empty DataSet 55 | ```swift 56 | // set image, title, description 57 | tableView.setEmptyDataView(title: NSAttributedString(string: "NO COMMENTS AVAILABLE"), description: NSAttributedString(string: "Comments that you've posted will appear here."), image: UIImage(named: "nodata-comments"), background: nil) 58 | 59 | // or 60 | // customize background color 61 | tableView.setEmptyDataView(title: NSAttributedString(string: "No Data found"), description: nil, image: nil, background: RSEmptyDataBackground.color(color: UIColor.white)) 62 | 63 | // or 64 | // background view or image 65 | tableView.setEmptyDataView(title: nil, description: NSAttributedString(string: "No Results"), image: nil, background: RSEmptyDataBackground.view(view: imageView)) 66 | ``` 67 | 68 | ### PullToRefresh 69 | ```swift 70 | tableView.addPullToRefresh { [weak self] in 71 | 72 | // your code to handle pull to refresh action 73 | DispatchQueue.global().asyncAfter(deadline: .now()+2, execute: { 74 | 75 | // refresh data 76 | }) 77 | } 78 | 79 | // customize title and color 80 | tableView.setPullToRefresh(tintColor: UIColor.darkGray, attributedText: NSAttributedString(string: "Fetching data")) 81 | ``` 82 | 83 | ### Pagination 84 | ```swift 85 | tableView.addPagination { (page) in 86 | 87 | // url for next page 88 | let url = self?.getURLForPage(page) 89 | 90 | // fetch & append data 91 | self?.fetchDataFromServer(url: url!, completion: { (list) in 92 | self?.dataSource?.appendData(data: list) 93 | }) 94 | } 95 | 96 | // set pagination parameters (Default: Start = 0 & Size = 20) 97 | 98 | let paginationParams = PaginationParameters(page: 1, size: 50) 99 | tableView.addPagination(parameters: paginationParams) { [weak self] (page) in 100 | } 101 | ``` 102 | 103 | ### SearchBar 104 | ```swift 105 | tableView.addSearchBar() 106 | 107 | // or 108 | tableView.addSearchBar(placeHolder: "Search..", noResultMessage: NSAttributedString(string: "No result matching your search criteria")) 109 | 110 | // search handler 111 | dataSource?.searchResultHandler = { [weak self] (searchString, dataArray) in 112 | 113 | // filter 114 | let result = dataArray.filter({ $0.email.starts(with: searchString) }) 115 | self?.dataSource?.setSearchResultData(result, replace: false) 116 | 117 | // Note: 118 | // replace: true - will replace your main dataSource (use in case you want to search data from web) 119 | // replace: false - will maintain your main dataSource (use in case you want to search within existing data) 120 | } 121 | ``` 122 | ### Loading Indicator 123 | ```swift 124 | tableView.showIndicator(title: NSAttributedString(string: "LOADING"), tintColor: UIColor.darkGray) 125 | ``` 126 | 127 | ### Networking 128 | ```swift 129 | // prepare request -> This returns array of comments 130 | let request = DataModelRequest<[Comment]>(url: "URL Here") 131 | 132 | // execute request 133 | request.execute(success: { [weak self] (comments) in 134 | self?.dataSource?.appendData(data: comments) 135 | 136 | }) { [weak self] (error) in 137 | self?.tableView.hideAllAnimations() 138 | } 139 | 140 | // or 141 | // JSON Request 142 | let jsonrequest = JSONRequest(url: "", method: .POST, headers: nil, parameters: nil, responeKeyPath: "data") 143 | 144 | // Note: Specify keypath here, if you want only key specific json data 145 | // "data" or "data.contents" etc. 146 | ``` 147 | 148 | ### DataSource Operations 149 | ```swift 150 | // append rows to datasource 151 | self.dataSource?.appendData(data: list) 152 | 153 | // append at top 154 | self.dataSource?.prependData(data: list) 155 | 156 | // set or replace existing data with new 157 | self.dataSource?.setData(data: list) 158 | 159 | // clear 160 | self.dataSource?.clearData() 161 | ``` 162 | 163 | ### Network Reachabilty 164 | ```swift 165 | if ReachabilityManager.isReachable { 166 | // your code 167 | } 168 | 169 | // handler reachability changes 170 | NotificationCenter.default.addObserver(self, selector: #selector(handleReachabiltyChanges(notification:)), name: NSNotification.Name.init(reachabilityChangedNotification), object: nil) 171 | 172 | @objc func handleReachabiltyChanges(notification: Notification) { 173 | let isReachable = notification.userInfo?[reachabilityStatus] as? Bool ?? false 174 | 175 | if isReachable { 176 | // inform user 177 | } 178 | } 179 | ``` 180 | 181 | ### Example 182 | See [Example](https://github.com/rushisangani/RSMasterTableViewKit/tree/master/RSMasterTableViewKitExample) for more details. 183 | 184 | ## License 185 | 186 | RSMasterTableViewKit is released under the MIT license. [See LICENSE](https://github.com/rushisangani/RSMasterTableViewKit/blob/master/LICENSE) for details. 187 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-RSMasterTableViewKitExample/Pods-RSMasterTableViewKitExample-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 7 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # frameworks to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 13 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 14 | 15 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 16 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 17 | 18 | # Used as a return value for each invocation of `strip_invalid_archs` function. 19 | STRIP_BINARY_RETVAL=0 20 | 21 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 22 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 23 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 24 | 25 | # Copies and strips a vendored framework 26 | install_framework() 27 | { 28 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 29 | local source="${BUILT_PRODUCTS_DIR}/$1" 30 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 31 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 32 | elif [ -r "$1" ]; then 33 | local source="$1" 34 | fi 35 | 36 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 37 | 38 | if [ -L "${source}" ]; then 39 | echo "Symlinked..." 40 | source="$(readlink "${source}")" 41 | fi 42 | 43 | # Use filter instead of exclude so missing patterns don't throw errors. 44 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 45 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 46 | 47 | local basename 48 | basename="$(basename -s .framework "$1")" 49 | binary="${destination}/${basename}.framework/${basename}" 50 | if ! [ -r "$binary" ]; then 51 | binary="${destination}/${basename}" 52 | fi 53 | 54 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 55 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 56 | strip_invalid_archs "$binary" 57 | fi 58 | 59 | # Resign the code if required by the build settings to avoid unstable apps 60 | code_sign_if_enabled "${destination}/$(basename "$1")" 61 | 62 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 63 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 64 | local swift_runtime_libs 65 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 66 | for lib in $swift_runtime_libs; do 67 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 68 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 69 | code_sign_if_enabled "${destination}/${lib}" 70 | done 71 | fi 72 | } 73 | 74 | # Copies and strips a vendored dSYM 75 | install_dsym() { 76 | local source="$1" 77 | if [ -r "$source" ]; then 78 | # Copy the dSYM into a the targets temp dir. 79 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 80 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 81 | 82 | local basename 83 | basename="$(basename -s .framework.dSYM "$source")" 84 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" 85 | 86 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 87 | if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then 88 | strip_invalid_archs "$binary" 89 | fi 90 | 91 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 92 | # Move the stripped file into its final destination. 93 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 94 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 95 | else 96 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 97 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" 98 | fi 99 | fi 100 | } 101 | 102 | # Signs a framework with the provided identity 103 | code_sign_if_enabled() { 104 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 105 | # Use the current code_sign_identitiy 106 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 107 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 108 | 109 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 110 | code_sign_cmd="$code_sign_cmd &" 111 | fi 112 | echo "$code_sign_cmd" 113 | eval "$code_sign_cmd" 114 | fi 115 | } 116 | 117 | # Strip invalid architectures 118 | strip_invalid_archs() { 119 | binary="$1" 120 | # Get architectures for current target binary 121 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 122 | # Intersect them with the architectures we are building for 123 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 124 | # If there are no archs supported by this binary then warn the user 125 | if [[ -z "$intersected_archs" ]]; then 126 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 127 | STRIP_BINARY_RETVAL=0 128 | return 129 | fi 130 | stripped="" 131 | for arch in $binary_archs; do 132 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 133 | # Strip non-valid architectures in-place 134 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 135 | stripped="$stripped $arch" 136 | fi 137 | done 138 | if [[ "$stripped" ]]; then 139 | echo "Stripped $binary of architectures:$stripped" 140 | fi 141 | STRIP_BINARY_RETVAL=1 142 | } 143 | 144 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 145 | wait 146 | fi 147 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSTableView/RSTableViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSTableViewDataSource.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | 27 | import UIKit 28 | 29 | /// DataSource 30 | public typealias DataSource = [T] 31 | 32 | /// FilteredDataSource 33 | public typealias FilteredDataSource = [T] 34 | 35 | /// SearchHandler 36 | public typealias SearchResultHandler = ((String, DataSource) -> ()) 37 | 38 | /// RSTableViewDataSourceUpdate to handle data source updating 39 | protocol RSTableViewDataSourceUpdate: class { 40 | 41 | /// To be called when new dataSource value is set 42 | func didSetDataSource(count: Int) 43 | 44 | /// To be called when new data is added to dataSource 45 | func didAddedToDataSource(start: Int, withTotalCount count: Int) 46 | 47 | /// To be called when data is updated at index in dataSource 48 | func didUpdatedDataSourceAt(index: Int) 49 | 50 | /// To be called when data is deleted at index in dataSource 51 | func didDeletedDataDataSourceAt(index: Int) 52 | 53 | /// To be called when all data is removed from dataSource 54 | func didRemovedData(showEmptyState: Bool) 55 | 56 | /// To be called when data is set as search result 57 | func didSetSearchResultData(count: Int, replace: Bool) 58 | 59 | /// To be called when dataSourced is updated 60 | func refreshData() 61 | } 62 | 63 | /// RSTableViewDataSource 64 | open class RSTableViewDataSource: NSObject, UITableViewDataSource { 65 | 66 | // MARK: - Properties 67 | 68 | /// data source for tableview 69 | var dataSource: DataSource = [] { 70 | didSet { 71 | filteredDataSource = dataSource 72 | } 73 | } 74 | 75 | /// filtered data source for tableView 76 | var filteredDataSource: FilteredDataSource = [] 77 | 78 | // MARK: - Public 79 | 80 | /// get datasource array 81 | public var array: FilteredDataSource { 82 | return Array(arrayLiteral: self.filteredDataSource) as! FilteredDataSource 83 | } 84 | 85 | /// Search Result Handler 86 | public var searchResultHandler: SearchResultHandler? 87 | 88 | /// get datasource count 89 | public var count: Int { 90 | return filteredDataSource.count 91 | } 92 | 93 | // MARK: - Private 94 | 95 | /// datasource update delegate 96 | private weak var dataSourceUpdateDelegate: RSTableViewDataSourceUpdate? 97 | 98 | /// cell configuration - (cell, dataObject, indexPath) 99 | private var cellConfiguration: UITableViewCellConfiguration? 100 | 101 | /// cell identifier 102 | private var cellIdentifier: String! 103 | 104 | /// tableview for datasource 105 | private weak var tableView: RSTableView? 106 | 107 | 108 | // MARK: - Initialize 109 | 110 | public init(tableView: RSTableView, identifier: String, cellConfiguration: @escaping UITableViewCellConfiguration) { 111 | super.init() 112 | 113 | tableView.dataSource = self 114 | tableView.tableViewDataSourceDelegate = self 115 | dataSourceUpdateDelegate = tableView 116 | 117 | self.tableView = tableView 118 | self.cellIdentifier = identifier 119 | self.cellConfiguration = cellConfiguration 120 | } 121 | 122 | // MARK: - UITableViewDataSource 123 | 124 | public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 125 | return self.filteredDataSource.count 126 | } 127 | 128 | public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 129 | 130 | // deque tableview cell 131 | let cell = tableView.dequeueReusableCell(withIdentifier: self.cellIdentifier, for: indexPath) 132 | 133 | // cell configuration 134 | if let config = cellConfiguration { 135 | 136 | let dataObject = self.objectAt(indexPath: indexPath) 137 | config(cell, dataObject, indexPath) 138 | } 139 | return cell 140 | } 141 | } 142 | 143 | // MARK: - Public 144 | extension RSTableViewDataSource { 145 | 146 | /// returns the object present in dataSourceArray at specified indexPath 147 | public func objectAt(indexPath: IndexPath) -> T { 148 | return self.filteredDataSource[indexPath.row] 149 | } 150 | 151 | /// sets data in datasource 152 | public func setData(data: DataSource) { 153 | self.dataSource = data 154 | self.dataSourceUpdateDelegate?.didSetDataSource(count: data.count) 155 | } 156 | 157 | /// append data in datasource 158 | public func appendData(data: DataSource) { 159 | 160 | let startIndex = self.dataSource.count 161 | self.dataSource.append(contentsOf: data) 162 | self.dataSourceUpdateDelegate?.didAddedToDataSource(start: startIndex, withTotalCount: data.count) 163 | } 164 | 165 | /// insert data at top 166 | public func prependData(data: DataSource) { 167 | for i in 0.., replace: Bool = false) { 187 | if replace { 188 | self.dataSource = data 189 | }else { 190 | self.filteredDataSource = data 191 | } 192 | self.dataSourceUpdateDelegate?.didSetSearchResultData(count: data.count, replace: replace) 193 | } 194 | 195 | /// clear all data 196 | public func clearData(showEmptyState: Bool = true) { 197 | self.dataSource = [] 198 | self.dataSourceUpdateDelegate?.didRemovedData(showEmptyState: showEmptyState) 199 | } 200 | } 201 | 202 | // MARK:- RSTableviewDataSourceDelegate 203 | extension RSTableViewDataSource: RSTableviewDataSourceDelegate { 204 | 205 | /// Update search 206 | func updateSearch(_ searchText: String) { 207 | if let handler = searchResultHandler { 208 | handler(searchText, self.dataSource) 209 | } 210 | } 211 | 212 | /// To get datasource array count 213 | func getCount() -> Int { 214 | return count 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Networking/NetworkManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkManager.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /************* Enums *****************/ 29 | 30 | /// Types of HTTP requests 31 | public enum HTTPMethod: String { 32 | case GET 33 | case POST 34 | case PUT 35 | case DELETE 36 | } 37 | 38 | /************* Error Codes **************/ 39 | 40 | /// Error codes 41 | let kNoInternetErrCode = -1 42 | let kInvalidURLErrCode = -2 43 | let kJSONParsingErrCode = -3 44 | let kModelConversionErrCode = -4 45 | let kHTTPErrCode = -5 46 | let kNoDataReturnedErrCode = -6 47 | let kDataConversionErrCode = -7 48 | 49 | 50 | /************* Strings **************/ 51 | 52 | /// Messages 53 | let mNoInternetConnection = "No Internet Connection!" 54 | let mkInternetConnected = "Internet Connected!" 55 | let mURLNotValid = "Invalid URL!" 56 | let mErrorInJSONParsing = "Error in json parsing" 57 | let mErrorInDataConversion = "Error in data conversion" 58 | let mErrorInModelConversion = "Error in data model conversion" 59 | let mNoDataReturned = "No data returned from server" 60 | let mNoDataFoundForKeyPath = "No data found for specified KeyPath" 61 | 62 | 63 | /// Network manager to handler all network requests 64 | open class NetworkManager { 65 | 66 | // MARK: - Singleton 67 | public static let shared = NetworkManager() 68 | 69 | // MARK: - Init 70 | private init() { 71 | ReachabilityManager.shared.initialize() 72 | } 73 | 74 | // MARK: - Properties 75 | 76 | /// Array of current tasks 77 | public var currentTasks: [URLSessionDataTask] = [] 78 | } 79 | 80 | // MARK:- Public 81 | extension NetworkManager { 82 | 83 | /** 84 | Execute Network Request 85 | */ 86 | public func execute(request: Request, responseType: ResponseType, success: @escaping ((Any) -> ()), failure: ((ResponseError) -> ())?) { 87 | 88 | // check for network reachability 89 | guard ReachabilityManager.isReachable else { 90 | self.showError(ResponseError(kNoInternetErrCode, mNoInternetConnection), failure: failure) 91 | return 92 | } 93 | 94 | // check for URL 95 | guard !request.url.isEmpty, let httpURL = URL(string: request.url) else { 96 | self.showError(ResponseError(kInvalidURLErrCode, mURLNotValid), failure: failure) 97 | return 98 | } 99 | 100 | // cancel previous request if same is exists 101 | self.cancelTaskForURL(httpURL.absoluteString) 102 | 103 | // create request 104 | var urlRequest = URLRequest(url: httpURL) 105 | urlRequest.httpMethod = request.method.rawValue 106 | print(urlRequest.url?.absoluteString ?? "") 107 | 108 | // headers 109 | var httpHeaders = [String: String]() 110 | 111 | if let headers = request.headers, !headers.isEmpty { 112 | httpHeaders.merge(headers) { (_, new) in new } 113 | } 114 | urlRequest.allHTTPHeaderFields = httpHeaders 115 | 116 | // parameters 117 | if let params = request.parameters, !params.isEmpty { 118 | do { 119 | let jsonParameters = try JSONSerialization.data(withJSONObject: params, options: []) 120 | urlRequest.httpBody = jsonParameters 121 | 122 | let paramString = String(data: jsonParameters, encoding: .utf8) 123 | print(paramString ?? "") 124 | }catch { 125 | print("Unable to add parameters in request.") 126 | } 127 | } 128 | 129 | // start data task 130 | let dataTask = URLSession.shared.dataTask(with: urlRequest) { [weak self] (data, response, error) in 131 | 132 | // remove completed task 133 | self?.removeTaskForURL(urlRequest.url?.absoluteString ?? "") 134 | 135 | // http error check 136 | if let httpError = error { 137 | self?.showError(ResponseError(kHTTPErrCode, httpError.localizedDescription), failure: failure) 138 | return 139 | } 140 | 141 | // response data check 142 | guard let responseData = data else { 143 | self?.showError(ResponseError(kNoDataReturnedErrCode, mNoDataReturned), failure: failure) 144 | return 145 | } 146 | 147 | // Get data as JSON 148 | guard var json = try? JSONSerialization.jsonObject(with: responseData, options: []) else { 149 | self?.showError(ResponseError(kJSONParsingErrCode, mErrorInJSONParsing), failure: failure) 150 | return 151 | } 152 | 153 | // print response 154 | print(json) 155 | 156 | // get value for specified keypath if exists 157 | if let path = request.responeKeyPath, 158 | !path.isEmpty, let dataObject = (json as! NSDictionary).value(forKeyPath: path) { 159 | json = dataObject 160 | } 161 | 162 | // send response if type is JSON 163 | if responseType == .json { 164 | success(json) 165 | return 166 | } 167 | 168 | /// convert json to data 169 | if let jsonData = try? JSONSerialization.data(withJSONObject: json, options: []) { 170 | success(jsonData) 171 | }else { 172 | self?.showError(ResponseError(kDataConversionErrCode, mErrorInDataConversion), failure: failure) 173 | } 174 | } 175 | 176 | // set data task properties 177 | dataTask.taskDescription = request.url 178 | 179 | // add to current tasks 180 | self.currentTasks.append(dataTask) 181 | 182 | // start 183 | dataTask.resume() 184 | } 185 | 186 | /// Cancel Data Task 187 | public func cancelTaskForURL(_ url: String) { 188 | 189 | // find task for url and cancel it 190 | if let index = currentTasks.firstIndex(where: { $0.taskDescription == url }) { 191 | 192 | let dataTask = currentTasks[index] 193 | dataTask.cancel() 194 | currentTasks.remove(at: index) 195 | } 196 | } 197 | } 198 | 199 | // MARK:- Private 200 | extension NetworkManager { 201 | 202 | /// Remove task from currentTasks 203 | private func removeTaskForURL(_ url: String) { 204 | 205 | // find task for url and remove it 206 | if let index = currentTasks.firstIndex(where: { $0.taskDescription == url }) { 207 | currentTasks.remove(at: index) 208 | } 209 | } 210 | 211 | /// Show error message 212 | private func showError(_ error: ResponseError, failure: ((ResponseError) -> ())?) { 213 | guard let failure = failure else { return } 214 | 215 | DispatchQueue.main.async { 216 | failure(error) 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /RSMasterTableViewKitExample/RSMasterTableViewKitExample/Base.lproj/Main.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 | 29 | 30 | 31 | 32 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSEmptyDataSet/RSEmptyDataView.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 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.framework/Headers/RSMasterTableViewKit-Swift.h: -------------------------------------------------------------------------------- 1 | // Generated by Apple Swift version 4.1.2 (swiftlang-902.0.54 clang-902.0.39.2) 2 | #pragma clang diagnostic push 3 | #pragma clang diagnostic ignored "-Wgcc-compat" 4 | 5 | #if !defined(__has_include) 6 | # define __has_include(x) 0 7 | #endif 8 | #if !defined(__has_attribute) 9 | # define __has_attribute(x) 0 10 | #endif 11 | #if !defined(__has_feature) 12 | # define __has_feature(x) 0 13 | #endif 14 | #if !defined(__has_warning) 15 | # define __has_warning(x) 0 16 | #endif 17 | 18 | #if __has_include() 19 | # include 20 | #endif 21 | 22 | #pragma clang diagnostic ignored "-Wauto-import" 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #if !defined(SWIFT_TYPEDEFS) 29 | # define SWIFT_TYPEDEFS 1 30 | # if __has_include() 31 | # include 32 | # elif !defined(__cplusplus) 33 | typedef uint_least16_t char16_t; 34 | typedef uint_least32_t char32_t; 35 | # endif 36 | typedef float swift_float2 __attribute__((__ext_vector_type__(2))); 37 | typedef float swift_float3 __attribute__((__ext_vector_type__(3))); 38 | typedef float swift_float4 __attribute__((__ext_vector_type__(4))); 39 | typedef double swift_double2 __attribute__((__ext_vector_type__(2))); 40 | typedef double swift_double3 __attribute__((__ext_vector_type__(3))); 41 | typedef double swift_double4 __attribute__((__ext_vector_type__(4))); 42 | typedef int swift_int2 __attribute__((__ext_vector_type__(2))); 43 | typedef int swift_int3 __attribute__((__ext_vector_type__(3))); 44 | typedef int swift_int4 __attribute__((__ext_vector_type__(4))); 45 | typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); 46 | typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); 47 | typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); 48 | #endif 49 | 50 | #if !defined(SWIFT_PASTE) 51 | # define SWIFT_PASTE_HELPER(x, y) x##y 52 | # define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) 53 | #endif 54 | #if !defined(SWIFT_METATYPE) 55 | # define SWIFT_METATYPE(X) Class 56 | #endif 57 | #if !defined(SWIFT_CLASS_PROPERTY) 58 | # if __has_feature(objc_class_property) 59 | # define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ 60 | # else 61 | # define SWIFT_CLASS_PROPERTY(...) 62 | # endif 63 | #endif 64 | 65 | #if __has_attribute(objc_runtime_name) 66 | # define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) 67 | #else 68 | # define SWIFT_RUNTIME_NAME(X) 69 | #endif 70 | #if __has_attribute(swift_name) 71 | # define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) 72 | #else 73 | # define SWIFT_COMPILE_NAME(X) 74 | #endif 75 | #if __has_attribute(objc_method_family) 76 | # define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) 77 | #else 78 | # define SWIFT_METHOD_FAMILY(X) 79 | #endif 80 | #if __has_attribute(noescape) 81 | # define SWIFT_NOESCAPE __attribute__((noescape)) 82 | #else 83 | # define SWIFT_NOESCAPE 84 | #endif 85 | #if __has_attribute(warn_unused_result) 86 | # define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) 87 | #else 88 | # define SWIFT_WARN_UNUSED_RESULT 89 | #endif 90 | #if __has_attribute(noreturn) 91 | # define SWIFT_NORETURN __attribute__((noreturn)) 92 | #else 93 | # define SWIFT_NORETURN 94 | #endif 95 | #if !defined(SWIFT_CLASS_EXTRA) 96 | # define SWIFT_CLASS_EXTRA 97 | #endif 98 | #if !defined(SWIFT_PROTOCOL_EXTRA) 99 | # define SWIFT_PROTOCOL_EXTRA 100 | #endif 101 | #if !defined(SWIFT_ENUM_EXTRA) 102 | # define SWIFT_ENUM_EXTRA 103 | #endif 104 | #if !defined(SWIFT_CLASS) 105 | # if __has_attribute(objc_subclassing_restricted) 106 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA 107 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 108 | # else 109 | # define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 110 | # define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA 111 | # endif 112 | #endif 113 | 114 | #if !defined(SWIFT_PROTOCOL) 115 | # define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 116 | # define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA 117 | #endif 118 | 119 | #if !defined(SWIFT_EXTENSION) 120 | # define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) 121 | #endif 122 | 123 | #if !defined(OBJC_DESIGNATED_INITIALIZER) 124 | # if __has_attribute(objc_designated_initializer) 125 | # define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) 126 | # else 127 | # define OBJC_DESIGNATED_INITIALIZER 128 | # endif 129 | #endif 130 | #if !defined(SWIFT_ENUM_ATTR) 131 | # if defined(__has_attribute) && __has_attribute(enum_extensibility) 132 | # define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open))) 133 | # else 134 | # define SWIFT_ENUM_ATTR 135 | # endif 136 | #endif 137 | #if !defined(SWIFT_ENUM) 138 | # define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type 139 | # if __has_feature(generalized_swift_name) 140 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type 141 | # else 142 | # define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) 143 | # endif 144 | #endif 145 | #if !defined(SWIFT_UNAVAILABLE) 146 | # define SWIFT_UNAVAILABLE __attribute__((unavailable)) 147 | #endif 148 | #if !defined(SWIFT_UNAVAILABLE_MSG) 149 | # define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) 150 | #endif 151 | #if !defined(SWIFT_AVAILABILITY) 152 | # define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) 153 | #endif 154 | #if !defined(SWIFT_DEPRECATED) 155 | # define SWIFT_DEPRECATED __attribute__((deprecated)) 156 | #endif 157 | #if !defined(SWIFT_DEPRECATED_MSG) 158 | # define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) 159 | #endif 160 | #if __has_feature(attribute_diagnose_if_objc) 161 | # define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) 162 | #else 163 | # define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) 164 | #endif 165 | #if __has_feature(modules) 166 | @import ObjectiveC; 167 | @import UIKit; 168 | @import CoreGraphics; 169 | @import Foundation; 170 | #endif 171 | 172 | #pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" 173 | #pragma clang diagnostic ignored "-Wduplicate-method-arg" 174 | #if __has_warning("-Wpragma-clang-attribute") 175 | # pragma clang diagnostic ignored "-Wpragma-clang-attribute" 176 | #endif 177 | #pragma clang diagnostic ignored "-Wunknown-pragmas" 178 | #pragma clang diagnostic ignored "-Wnullability" 179 | 180 | #if __has_attribute(external_source_symbol) 181 | # pragma push_macro("any") 182 | # undef any 183 | # pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="RSMasterTableViewKit",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) 184 | # pragma pop_macro("any") 185 | #endif 186 | 187 | 188 | @interface NSObject (SWIFT_EXTENSION(RSMasterTableViewKit)) 189 | - (NSDictionary * _Nonnull)toDictionary SWIFT_WARN_UNUSED_RESULT; 190 | @end 191 | 192 | @class NSCoder; 193 | 194 | SWIFT_CLASS("_TtC20RSMasterTableViewKit15RSEmptyDataView") 195 | @interface RSEmptyDataView : UIView 196 | - (void)awakeFromNib; 197 | - (nonnull instancetype)initWithFrame:(CGRect)frame OBJC_DESIGNATED_INITIALIZER; 198 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 199 | @end 200 | 201 | 202 | /// RSSearchController 203 | SWIFT_CLASS("_TtC20RSMasterTableViewKit18RSSearchController") 204 | @interface RSSearchController : NSObject 205 | - (nonnull instancetype)init SWIFT_UNAVAILABLE; 206 | + (nonnull instancetype)new SWIFT_DEPRECATED_MSG("-init is unavailable"); 207 | @end 208 | 209 | 210 | 211 | @class UISearchController; 212 | 213 | @interface RSSearchController (SWIFT_EXTENSION(RSMasterTableViewKit)) 214 | - (void)updateSearchResultsForSearchController:(UISearchController * _Nonnull)searchController; 215 | - (void)willPresentSearchController:(UISearchController * _Nonnull)searchController; 216 | @end 217 | 218 | 219 | /// RSTableView 220 | SWIFT_CLASS("_TtC20RSMasterTableViewKit11RSTableView") 221 | @interface RSTableView : UITableView 222 | - (void)awakeFromNib; 223 | - (nonnull instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER; 224 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 225 | @end 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | @interface RSTableView (SWIFT_EXTENSION(RSMasterTableViewKit)) 235 | - (void)tableView:(UITableView * _Nonnull)tableView prefetchRowsAtIndexPaths:(NSArray * _Nonnull)indexPaths; 236 | @end 237 | 238 | 239 | 240 | 241 | 242 | 243 | /// RSTableViewCell 244 | SWIFT_CLASS("_TtC20RSMasterTableViewKit15RSTableViewCell") 245 | @interface RSTableViewCell : UITableViewCell 246 | - (nonnull instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString * _Nullable)reuseIdentifier OBJC_DESIGNATED_INITIALIZER SWIFT_AVAILABILITY(ios,introduced=3.0); 247 | - (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER; 248 | @end 249 | 250 | 251 | 252 | 253 | 254 | #if __has_attribute(external_source_symbol) 255 | # pragma clang attribute pop 256 | #endif 257 | #pragma clang diagnostic pop 258 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/Reachability/Reachability.swift: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014, Ashley Mills 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | import SystemConfiguration 29 | import Foundation 30 | 31 | public enum ReachabilityError: Error { 32 | case FailedToCreateWithAddress(sockaddr_in) 33 | case FailedToCreateWithHostname(String) 34 | case UnableToSetCallback 35 | case UnableToSetDispatchQueue 36 | } 37 | 38 | @available(*, unavailable, renamed: "Notification.Name.reachabilityChanged") 39 | public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification") 40 | 41 | extension Notification.Name { 42 | public static let reachabilityChanged = Notification.Name("reachabilityChanged") 43 | } 44 | 45 | func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) { 46 | 47 | guard let info = info else { return } 48 | 49 | let reachability = Unmanaged.fromOpaque(info).takeUnretainedValue() 50 | reachability.reachabilityChanged() 51 | } 52 | 53 | public class Reachability { 54 | 55 | public typealias NetworkReachable = (Reachability) -> () 56 | public typealias NetworkUnreachable = (Reachability) -> () 57 | 58 | @available(*, unavailable, renamed: "Conection") 59 | public enum NetworkStatus: CustomStringConvertible { 60 | case notReachable, reachableViaWiFi, reachableViaWWAN 61 | public var description: String { 62 | switch self { 63 | case .reachableViaWWAN: return "Cellular" 64 | case .reachableViaWiFi: return "WiFi" 65 | case .notReachable: return "No Connection" 66 | } 67 | } 68 | } 69 | 70 | public enum Connection: CustomStringConvertible { 71 | case none, wifi, cellular 72 | public var description: String { 73 | switch self { 74 | case .cellular: return "Cellular" 75 | case .wifi: return "WiFi" 76 | case .none: return "No Connection" 77 | } 78 | } 79 | } 80 | 81 | public var whenReachable: NetworkReachable? 82 | public var whenUnreachable: NetworkUnreachable? 83 | 84 | @available(*, deprecated, renamed: "allowsCellularConnection") 85 | public let reachableOnWWAN: Bool = true 86 | 87 | /// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`) 88 | public var allowsCellularConnection: Bool 89 | 90 | // The notification center on which "reachability changed" events are being posted 91 | public var notificationCenter: NotificationCenter = NotificationCenter.default 92 | 93 | @available(*, deprecated, renamed: "connection.description") 94 | public var currentReachabilityString: String { 95 | return "\(connection)" 96 | } 97 | 98 | @available(*, unavailable, renamed: "connection") 99 | public var currentReachabilityStatus: Connection { 100 | return connection 101 | } 102 | 103 | public var connection: Connection { 104 | 105 | guard isReachableFlagSet else { return .none } 106 | 107 | // If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi 108 | guard isRunningOnDevice else { return .wifi } 109 | 110 | var connection = Connection.none 111 | 112 | if !isConnectionRequiredFlagSet { 113 | connection = .wifi 114 | } 115 | 116 | if isConnectionOnTrafficOrDemandFlagSet { 117 | if !isInterventionRequiredFlagSet { 118 | connection = .wifi 119 | } 120 | } 121 | 122 | if isOnWWANFlagSet { 123 | if !allowsCellularConnection { 124 | connection = .none 125 | } else { 126 | connection = .cellular 127 | } 128 | } 129 | 130 | return connection 131 | } 132 | 133 | fileprivate var previousFlags: SCNetworkReachabilityFlags? 134 | 135 | fileprivate var isRunningOnDevice: Bool = { 136 | #if targetEnvironment(simulator) 137 | return false 138 | #else 139 | return true 140 | #endif 141 | }() 142 | 143 | fileprivate var notifierRunning = false 144 | fileprivate let reachabilityRef: SCNetworkReachability 145 | 146 | fileprivate let reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability") 147 | 148 | required public init(reachabilityRef: SCNetworkReachability) { 149 | allowsCellularConnection = true 150 | self.reachabilityRef = reachabilityRef 151 | } 152 | 153 | public convenience init?(hostname: String) { 154 | 155 | guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { return nil } 156 | 157 | self.init(reachabilityRef: ref) 158 | } 159 | 160 | public convenience init?() { 161 | 162 | var zeroAddress = sockaddr() 163 | zeroAddress.sa_len = UInt8(MemoryLayout.size) 164 | zeroAddress.sa_family = sa_family_t(AF_INET) 165 | 166 | guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { return nil } 167 | 168 | self.init(reachabilityRef: ref) 169 | } 170 | 171 | deinit { 172 | stopNotifier() 173 | } 174 | } 175 | 176 | public extension Reachability { 177 | 178 | // MARK: - *** Notifier methods *** 179 | func startNotifier() throws { 180 | 181 | guard !notifierRunning else { return } 182 | 183 | var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) 184 | context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) 185 | if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) { 186 | stopNotifier() 187 | throw ReachabilityError.UnableToSetCallback 188 | } 189 | 190 | if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) { 191 | stopNotifier() 192 | throw ReachabilityError.UnableToSetDispatchQueue 193 | } 194 | 195 | // Perform an initial check 196 | reachabilitySerialQueue.async { 197 | self.reachabilityChanged() 198 | } 199 | 200 | notifierRunning = true 201 | } 202 | 203 | func stopNotifier() { 204 | defer { notifierRunning = false } 205 | 206 | SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil) 207 | SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil) 208 | } 209 | 210 | // MARK: - *** Connection test methods *** 211 | @available(*, deprecated, message: "Please use `connection != .none`") 212 | var isReachable: Bool { 213 | 214 | guard isReachableFlagSet else { return false } 215 | 216 | if isConnectionRequiredAndTransientFlagSet { 217 | return false 218 | } 219 | 220 | if isRunningOnDevice { 221 | if isOnWWANFlagSet && !reachableOnWWAN { 222 | // We don't want to connect when on cellular connection 223 | return false 224 | } 225 | } 226 | 227 | return true 228 | } 229 | 230 | @available(*, deprecated, message: "Please use `connection == .cellular`") 231 | var isReachableViaWWAN: Bool { 232 | // Check we're not on the simulator, we're REACHABLE and check we're on WWAN 233 | return isRunningOnDevice && isReachableFlagSet && isOnWWANFlagSet 234 | } 235 | 236 | @available(*, deprecated, message: "Please use `connection == .wifi`") 237 | var isReachableViaWiFi: Bool { 238 | 239 | // Check we're reachable 240 | guard isReachableFlagSet else { return false } 241 | 242 | // If reachable we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi 243 | guard isRunningOnDevice else { return true } 244 | 245 | // Check we're NOT on WWAN 246 | return !isOnWWANFlagSet 247 | } 248 | 249 | var description: String { 250 | 251 | let W = isRunningOnDevice ? (isOnWWANFlagSet ? "W" : "-") : "X" 252 | let R = isReachableFlagSet ? "R" : "-" 253 | let c = isConnectionRequiredFlagSet ? "c" : "-" 254 | let t = isTransientConnectionFlagSet ? "t" : "-" 255 | let i = isInterventionRequiredFlagSet ? "i" : "-" 256 | let C = isConnectionOnTrafficFlagSet ? "C" : "-" 257 | let D = isConnectionOnDemandFlagSet ? "D" : "-" 258 | let l = isLocalAddressFlagSet ? "l" : "-" 259 | let d = isDirectFlagSet ? "d" : "-" 260 | 261 | return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)" 262 | } 263 | } 264 | 265 | fileprivate extension Reachability { 266 | 267 | func reachabilityChanged() { 268 | guard previousFlags != flags else { return } 269 | 270 | let block = connection != .none ? whenReachable : whenUnreachable 271 | 272 | DispatchQueue.main.async { 273 | block?(self) 274 | self.notificationCenter.post(name: .reachabilityChanged, object:self) 275 | } 276 | 277 | previousFlags = flags 278 | } 279 | 280 | var isOnWWANFlagSet: Bool { 281 | #if os(iOS) 282 | return flags.contains(.isWWAN) 283 | #else 284 | return false 285 | #endif 286 | } 287 | var isReachableFlagSet: Bool { 288 | return flags.contains(.reachable) 289 | } 290 | var isConnectionRequiredFlagSet: Bool { 291 | return flags.contains(.connectionRequired) 292 | } 293 | var isInterventionRequiredFlagSet: Bool { 294 | return flags.contains(.interventionRequired) 295 | } 296 | var isConnectionOnTrafficFlagSet: Bool { 297 | return flags.contains(.connectionOnTraffic) 298 | } 299 | var isConnectionOnDemandFlagSet: Bool { 300 | return flags.contains(.connectionOnDemand) 301 | } 302 | var isConnectionOnTrafficOrDemandFlagSet: Bool { 303 | return !flags.intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty 304 | } 305 | var isTransientConnectionFlagSet: Bool { 306 | return flags.contains(.transientConnection) 307 | } 308 | var isLocalAddressFlagSet: Bool { 309 | return flags.contains(.isLocalAddress) 310 | } 311 | var isDirectFlagSet: Bool { 312 | return flags.contains(.isDirect) 313 | } 314 | var isConnectionRequiredAndTransientFlagSet: Bool { 315 | return flags.intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection] 316 | } 317 | 318 | var flags: SCNetworkReachabilityFlags { 319 | var flags = SCNetworkReachabilityFlags() 320 | if SCNetworkReachabilityGetFlags(reachabilityRef, &flags) { 321 | return flags 322 | } else { 323 | return SCNetworkReachabilityFlags() 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit/RSTableView/RSTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RSTableView.swift 3 | // RSMasterTableViewKit 4 | // 5 | // Copyright (c) 2018 Rushi Sangani 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import UIKit 27 | 28 | /// TableviewDataSourceDelegate to get values of RSTableViewDataSource 29 | protocol RSTableviewDataSourceDelegate: class { 30 | 31 | /// Update Search 32 | func updateSearch(_ searchText: String) 33 | 34 | /// To get total item count 35 | func getCount() -> Int 36 | } 37 | 38 | /// RSTableView 39 | open class RSTableView: UITableView { 40 | 41 | // MARK: - Properties 42 | 43 | // MARK: - Private 44 | 45 | /// Pull To Refresh control 46 | lazy private var pullToRefresh: UIRefreshControl = { 47 | 48 | let refreshControl = UIRefreshControl() 49 | refreshControl.addTarget(self, action: #selector(handlePullToRefresh), for: .valueChanged) 50 | return refreshControl 51 | }() 52 | 53 | /// PullToRefresh handler 54 | private var pullToRefreshHandler: PullToRefreshHandler? 55 | 56 | /// Pagination handler 57 | private var paginationHanlder: PaginationHandler? 58 | 59 | /// checks if should fetch more data for pagination 60 | private var shouldFetchMoreData: Bool = false 61 | 62 | /// This is to manage current status of the infinite scrolling 63 | private var pageRequestStatus: PageRequestStatus = .none 64 | 65 | /// Empty data view 66 | lazy private var emptyDataView: RSEmptyDataView = { 67 | 68 | let view: RSEmptyDataView = UIView.loadFromNib() 69 | view.frame = self.bounds 70 | backgroundView = view 71 | return view 72 | }() 73 | 74 | /// RSTableViewDataSource delegate 75 | weak var tableViewDataSourceDelegate: RSTableviewDataSourceDelegate! 76 | 77 | /// SearchBar delegate 78 | var searchBarDelegate: RSSearchBarDelegate? 79 | 80 | /// FooterView 81 | lazy private var footerIndicatorView: UIActivityIndicatorView = { 82 | 83 | let indicator = UIActivityIndicatorView(style: .gray) 84 | indicator.color = UIColor.darkGray 85 | indicator.hidesWhenStopped = true 86 | return indicator 87 | }() 88 | 89 | // MARK: - Public 90 | 91 | /// SearchBar 92 | public var searchBar: UISearchBar? { 93 | return self.searchBarDelegate?.searchBar 94 | } 95 | 96 | /// Pagination Parameters 97 | public var paginationParameters: PaginationParameters? 98 | 99 | // MARK: - Life Cycle 100 | open override func awakeFromNib() { 101 | super.awakeFromNib() 102 | initialize() 103 | } 104 | 105 | /// Initialize 106 | private func initialize() { 107 | 108 | estimatedRowHeight = 50 109 | rowHeight = UITableView.automaticDimension 110 | tableFooterView = UIView() 111 | } 112 | 113 | // MARK: - Public 114 | 115 | /// Add PullToRefresh to tableview 116 | public func addPullToRefresh(handler: @escaping PullToRefreshHandler) { 117 | pullToRefreshHandler = handler 118 | self.insertSubview(pullToRefresh, at: 0) 119 | } 120 | 121 | /// Add Pagination 122 | public func addPagination(parameters: PaginationParameters? = PaginationParameters() , handler: @escaping PaginationHandler) { 123 | 124 | self.paginationParameters = parameters 125 | paginationHanlder = handler 126 | tableFooterView = footerIndicatorView 127 | if #available(iOS 10.0, *) { 128 | prefetchDataSource = self 129 | } 130 | } 131 | 132 | /// Add Searchbar 133 | public func addSearchBar(placeHolder: String? = nil, noResultMessage: NSAttributedString? = nil) { 134 | self.searchBarDelegate = RSSearchBarDelegate(placeHolder: placeHolder ?? mDefaultSearchPlaceHolder, message: noResultMessage) { [weak self] (searchString) in 135 | self?.tableViewDataSourceDelegate.updateSearch(searchString) 136 | } 137 | self.tableHeaderView = self.searchBarDelegate?.searchBar 138 | } 139 | } 140 | 141 | // MARK: - RSTableViewDataSourceUpdate 142 | extension RSTableView: RSTableViewDataSourceUpdate { 143 | 144 | /// new data updated in dataSource 145 | func didSetDataSource(count: Int) { 146 | 147 | // reload tableview 148 | reloadTableView { [weak self] in 149 | 150 | // update empty data set 151 | self?.updateEmptyDataState() 152 | 153 | // update fetch more data flag 154 | self?.updateShouldFetchMoreData(count: count) 155 | } 156 | } 157 | 158 | /// new data added in dataSource 159 | func didAddedToDataSource(start: Int, withTotalCount count: Int) { 160 | didSetDataSource(count: count) 161 | 162 | /* 163 | // add rows to tableView 164 | addRows(from: start, to: start + count, inSection: 0) { 165 | 166 | // scroll to new row 167 | if start < self.tableViewDataSourceDelegate.getCount() { 168 | self.scrollToRow(at: IndexPath(row: start, section: 0), at: UITableViewScrollPosition.bottom, animated: false) 169 | } 170 | 171 | // update fetch more data flag 172 | self.updateShouldFetchMoreData(count: count) 173 | } 174 | */ 175 | } 176 | 177 | /// search result set in dataSource 178 | func didSetSearchResultData(count: Int, replace: Bool) { 179 | 180 | reloadTableView { [weak self] in 181 | 182 | // check if no results 183 | if count == 0, let message = self?.searchBarDelegate?.noResultMessage { 184 | self?.emptyDataView.showNoSearchResultMessage(message) 185 | }else { 186 | self?.emptyDataView.hideNoSearchLabel() 187 | } 188 | 189 | // update fetch more data flag if content is replaced 190 | if replace { 191 | self?.updateShouldFetchMoreData(count: count) 192 | } 193 | } 194 | } 195 | 196 | /// data updated at specified index in dataSource 197 | func didUpdatedDataSourceAt(index: Int) { 198 | updateOrDeleteRows(indexPaths: [IndexPath(row: index, section: 0)], isUpdate: true) 199 | } 200 | 201 | /// data deleted at specified index in dataSource 202 | func didDeletedDataDataSourceAt(index: Int) { 203 | updateOrDeleteRows(indexPaths: [IndexPath(row: index, section: 0)], isUpdate: false) 204 | } 205 | 206 | /// all data removed from dataSource 207 | func didRemovedData(showEmptyState: Bool) { 208 | 209 | resetPagination() 210 | refreshData() 211 | 212 | // update empty data set, if true 213 | if showEmptyState { 214 | self.updateEmptyDataState() 215 | } 216 | } 217 | 218 | /// refresh data 219 | func refreshData() { 220 | reloadTableView() 221 | } 222 | } 223 | 224 | // MARK: - Indicator 225 | extension RSTableView { 226 | 227 | /// Show loading indicator 228 | public func showIndicator(title: NSAttributedString? = nil, tintColor: UIColor? = nil) { 229 | DispatchQueue.main.asyncAfter(deadline: .now()+0.1) { [weak self] in 230 | self?.emptyDataView.showLoadingIndicator(title: title) 231 | self?.showSearchBar(false) 232 | } 233 | } 234 | 235 | /// Hide loading indicator 236 | public func hideIndicator() { 237 | DispatchQueue.main.async { [weak self] in 238 | self?.emptyDataView.hideLoadingIndicator() 239 | } 240 | } 241 | 242 | /// Hides Loading Indicator, PullToRefresh, Load more 243 | public func hideAllAnimations() { 244 | 245 | // stop animations 246 | self.stopAnimations() 247 | 248 | // end pull to refresh 249 | self.endPullToRefresh() 250 | } 251 | } 252 | 253 | // MARK: - PullToRefresh 254 | extension RSTableView { 255 | 256 | // pull to refresh customization 257 | public func setPullToRefresh(tintColor: UIColor, attributedText: NSAttributedString? = nil) { 258 | pullToRefresh.tintColor = tintColor 259 | pullToRefresh.attributedTitle = attributedText 260 | } 261 | 262 | /// Ends pull to refresh animating 263 | public func endPullToRefresh() { 264 | guard self.isPullToRefreshAnimating() else { return } 265 | 266 | DispatchQueue.main.async { [weak self] in 267 | self?.pullToRefresh.endRefreshing() 268 | } 269 | } 270 | 271 | /// Pull To Refresh Handler 272 | @objc private func handlePullToRefresh() { 273 | searchBarDelegate?.searchBar?.resignFirstResponder() 274 | 275 | // reset 276 | resetBeforePullToReresh() 277 | 278 | // call handler 279 | if let handler = pullToRefreshHandler { 280 | handler() 281 | } 282 | } 283 | 284 | /// Checks if pull to refresh is animating 285 | private func isPullToRefreshAnimating() -> Bool { 286 | return pullToRefresh.isRefreshing 287 | } 288 | 289 | /// This will reset flags and hides animations 290 | private func resetBeforePullToReresh() { 291 | stopAnimations() 292 | resetPagination() 293 | } 294 | } 295 | 296 | // MARK: - EmptyDataView 297 | extension RSTableView { 298 | 299 | // empty data view set title, description and image 300 | public func setEmptyDataView(title: NSAttributedString?, description: NSAttributedString?, image: UIImage? = nil, background: RSEmptyDataBackground? = nil) { 301 | emptyDataView.setEmptyDataView(title: title, description: description, image: image, background: background) 302 | } 303 | 304 | /// Update empty data state 305 | private func updateEmptyDataState() { 306 | DispatchQueue.main.async { [weak self] in 307 | let show = (self?.tableViewDataSourceDelegate.getCount() == 0) 308 | self?.emptyDataView.showEmptyDataState(show) 309 | self?.showSearchBar(!show) 310 | } 311 | } 312 | } 313 | 314 | // MARK: - SearchBar 315 | extension RSTableView { 316 | 317 | /// Show Searchbar 318 | private func showSearchBar(_ show: Bool) { 319 | if show, let searchbar = self.searchBar { 320 | self.tableHeaderView = searchbar 321 | }else { 322 | self.tableHeaderView = nil 323 | } 324 | } 325 | } 326 | 327 | // MARK: - Pagination 328 | extension RSTableView: UITableViewDataSourcePrefetching { 329 | 330 | // prefetch rows 331 | public func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { 332 | 333 | guard indexPaths.count > 0, 334 | indexPaths.last?.row == tableViewDataSourceDelegate.getCount()-1, shouldFetchMoreData 335 | else { return } 336 | 337 | self.fetchMoreData() 338 | } 339 | 340 | /// Fetch more data, if not already started status 341 | private func fetchMoreData() { 342 | if pageRequestStatus == .started { return } 343 | 344 | // fetch next page data 345 | if let handler = self.paginationHanlder, let parameters = paginationParameters { 346 | footerIndicatorView.startAnimating() 347 | pageRequestStatus = .started 348 | 349 | // calculate next page 350 | paginationParameters?.currentPage = parameters.currentPage+1 351 | 352 | // calling handler 353 | handler(self.paginationParameters?.currentPage ?? parameters.startPage) 354 | } 355 | } 356 | 357 | /// Checks if need to fetch more data 358 | private func isPaginationEnabled() -> Bool { 359 | return (self.paginationHanlder != nil) 360 | } 361 | 362 | /// updates the pagination parameters 363 | private func updateShouldFetchMoreData(count: Int) { 364 | guard isPaginationEnabled() else { 365 | shouldFetchMoreData = false 366 | return 367 | } 368 | shouldFetchMoreData = (UInt(count) >= (paginationParameters?.size)!) 369 | } 370 | 371 | /// reset current page 372 | private func resetPagination() { 373 | shouldFetchMoreData = false 374 | if let pagination = paginationParameters { 375 | paginationParameters?.currentPage = pagination.startPage 376 | } 377 | } 378 | } 379 | 380 | // MARK: - UI Update & Animations 381 | extension RSTableView { 382 | 383 | /// reload tableview 384 | private func reloadTableView(completion: (() -> ())? = nil) { 385 | DispatchQueue.main.async { [weak self] in 386 | 387 | // hide animations 388 | self?.hideAllAnimations() 389 | 390 | // reload without animation 391 | UIView.setAnimationsEnabled(false) 392 | self?.reloadData() 393 | UIView.setAnimationsEnabled(true) 394 | 395 | // update page request status 396 | self?.pageRequestStatus = .none 397 | 398 | // call completion 399 | if let completion = completion { 400 | completion() 401 | } 402 | } 403 | } 404 | 405 | /// This function adds new rows to tableview 406 | private func addRows(from: Int, to: Int, inSection section:Int, completion: (() -> ())? = nil) { 407 | 408 | var indexPaths = [IndexPath]() 409 | for i in from.. /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 208 | showEnvVarsInLog = 0; 209 | }; 210 | /* End PBXShellScriptBuildPhase section */ 211 | 212 | /* Begin PBXSourcesBuildPhase section */ 213 | A294F78920530F4B00195712 /* Sources */ = { 214 | isa = PBXSourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | A294F79320530F4B00195712 /* DemoViewController.swift in Sources */, 218 | A2C648CC20CBE09C0011C0DD /* Comment.swift in Sources */, 219 | A294F79120530F4B00195712 /* AppDelegate.swift in Sources */, 220 | A2FC87AD205D8565000DB9EE /* MyTableViewCell.swift in Sources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXSourcesBuildPhase section */ 225 | 226 | /* Begin PBXVariantGroup section */ 227 | A294F79420530F4B00195712 /* Main.storyboard */ = { 228 | isa = PBXVariantGroup; 229 | children = ( 230 | A294F79520530F4B00195712 /* Base */, 231 | ); 232 | name = Main.storyboard; 233 | sourceTree = ""; 234 | }; 235 | A294F79920530F4B00195712 /* LaunchScreen.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | A294F79A20530F4B00195712 /* Base */, 239 | ); 240 | name = LaunchScreen.storyboard; 241 | sourceTree = ""; 242 | }; 243 | /* End PBXVariantGroup section */ 244 | 245 | /* Begin XCBuildConfiguration section */ 246 | A294F79D20530F4B00195712 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_NONNULL = YES; 251 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_COMMA = YES; 259 | CLANG_WARN_CONSTANT_CONVERSION = YES; 260 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 263 | CLANG_WARN_EMPTY_BODY = YES; 264 | CLANG_WARN_ENUM_CONVERSION = YES; 265 | CLANG_WARN_INFINITE_RECURSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 269 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 271 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 272 | CLANG_WARN_STRICT_PROTOTYPES = YES; 273 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 274 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | CODE_SIGN_IDENTITY = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = dwarf; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | ENABLE_TESTABILITY = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu11; 283 | GCC_DYNAMIC_NO_PIC = NO; 284 | GCC_NO_COMMON_BLOCKS = YES; 285 | GCC_OPTIMIZATION_LEVEL = 0; 286 | GCC_PREPROCESSOR_DEFINITIONS = ( 287 | "DEBUG=1", 288 | "$(inherited)", 289 | ); 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 297 | MTL_ENABLE_DEBUG_INFO = YES; 298 | ONLY_ACTIVE_ARCH = YES; 299 | SDKROOT = iphoneos; 300 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 301 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 302 | }; 303 | name = Debug; 304 | }; 305 | A294F79E20530F4B00195712 /* Release */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ALWAYS_SEARCH_USER_PATHS = NO; 309 | CLANG_ANALYZER_NONNULL = YES; 310 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 311 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 312 | CLANG_CXX_LIBRARY = "libc++"; 313 | CLANG_ENABLE_MODULES = YES; 314 | CLANG_ENABLE_OBJC_ARC = YES; 315 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_COMMA = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 322 | CLANG_WARN_EMPTY_BODY = YES; 323 | CLANG_WARN_ENUM_CONVERSION = YES; 324 | CLANG_WARN_INFINITE_RECURSION = YES; 325 | CLANG_WARN_INT_CONVERSION = YES; 326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | CODE_SIGN_IDENTITY = "iPhone Developer"; 337 | COPY_PHASE_STRIP = NO; 338 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 339 | ENABLE_NS_ASSERTIONS = NO; 340 | ENABLE_STRICT_OBJC_MSGSEND = YES; 341 | GCC_C_LANGUAGE_STANDARD = gnu11; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 350 | MTL_ENABLE_DEBUG_INFO = NO; 351 | SDKROOT = iphoneos; 352 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 353 | VALIDATE_PRODUCT = YES; 354 | }; 355 | name = Release; 356 | }; 357 | A294F7A020530F4B00195712 /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | baseConfigurationReference = 14090770F20DD10FE09930A8 /* Pods-RSMasterTableViewKitExample.debug.xcconfig */; 360 | buildSettings = { 361 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 362 | CODE_SIGN_STYLE = Manual; 363 | DEVELOPMENT_TEAM = ""; 364 | INFOPLIST_FILE = RSMasterTableViewKitExample/Info.plist; 365 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 366 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 367 | PRODUCT_BUNDLE_IDENTIFIER = com.rushi.RSMasterTableViewKitExample; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | PROVISIONING_PROFILE_SPECIFIER = ""; 370 | SWIFT_VERSION = 5.0; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | }; 373 | name = Debug; 374 | }; 375 | A294F7A120530F4B00195712 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | baseConfigurationReference = 9DE429C2D9D4A9A8C622E3C0 /* Pods-RSMasterTableViewKitExample.release.xcconfig */; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | CODE_SIGN_STYLE = Manual; 381 | DEVELOPMENT_TEAM = ""; 382 | INFOPLIST_FILE = RSMasterTableViewKitExample/Info.plist; 383 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 384 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 385 | PRODUCT_BUNDLE_IDENTIFIER = com.rushi.RSMasterTableViewKitExample; 386 | PRODUCT_NAME = "$(TARGET_NAME)"; 387 | PROVISIONING_PROFILE_SPECIFIER = ""; 388 | SWIFT_VERSION = 5.0; 389 | TARGETED_DEVICE_FAMILY = "1,2"; 390 | }; 391 | name = Release; 392 | }; 393 | /* End XCBuildConfiguration section */ 394 | 395 | /* Begin XCConfigurationList section */ 396 | A294F78820530F4B00195712 /* Build configuration list for PBXProject "RSMasterTableViewKitExample" */ = { 397 | isa = XCConfigurationList; 398 | buildConfigurations = ( 399 | A294F79D20530F4B00195712 /* Debug */, 400 | A294F79E20530F4B00195712 /* Release */, 401 | ); 402 | defaultConfigurationIsVisible = 0; 403 | defaultConfigurationName = Release; 404 | }; 405 | A294F79F20530F4B00195712 /* Build configuration list for PBXNativeTarget "RSMasterTableViewKitExample" */ = { 406 | isa = XCConfigurationList; 407 | buildConfigurations = ( 408 | A294F7A020530F4B00195712 /* Debug */, 409 | A294F7A120530F4B00195712 /* Release */, 410 | ); 411 | defaultConfigurationIsVisible = 0; 412 | defaultConfigurationName = Release; 413 | }; 414 | /* End XCConfigurationList section */ 415 | }; 416 | rootObject = A294F78520530F4B00195712 /* Project object */; 417 | } 418 | -------------------------------------------------------------------------------- /RSMasterTableViewKit/RSMasterTableViewKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 865D11492136C129007D8C47 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D11482136C129007D8C47 /* Reachability.swift */; }; 11 | 865D114B2136C1D2007D8C47 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D114A2136C1D2007D8C47 /* ReachabilityManager.swift */; }; 12 | 865D11532136C399007D8C47 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D114D2136C399007D8C47 /* NetworkManager.swift */; }; 13 | 865D11552136C399007D8C47 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D11502136C399007D8C47 /* Request.swift */; }; 14 | 865D11562136C399007D8C47 /* DataModelRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D11512136C399007D8C47 /* DataModelRequest.swift */; }; 15 | 865D11572136C399007D8C47 /* JSONRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 865D11522136C399007D8C47 /* JSONRequest.swift */; }; 16 | 8698C9B92137CA9D00719582 /* RSPagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698C9B82137CA9D00719582 /* RSPagination.swift */; }; 17 | 8698C9BB2137EE4900719582 /* RSSearchBarDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8698C9BA2137EE4900719582 /* RSSearchBarDelegate.swift */; }; 18 | A294F7C220530FD800195712 /* RSMasterTableViewKit.h in Headers */ = {isa = PBXBuildFile; fileRef = A294F7C020530FD800195712 /* RSMasterTableViewKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | A294F7D5205310AB00195712 /* RSTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A294F7D4205310AB00195712 /* RSTableView.swift */; }; 20 | A2BE66DD225CCBD800ED4E43 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2BE66DC225CCBD800ED4E43 /* Response.swift */; }; 21 | A2BE66E0225CCCB900ED4E43 /* ResponseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2BE66DF225CCCB900ED4E43 /* ResponseError.swift */; }; 22 | A2FC87A1205D2910000DB9EE /* RSTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2FC87A0205D2910000DB9EE /* RSTableViewDataSource.swift */; }; 23 | A2FC87A3205D377A000DB9EE /* RSTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2FC87A2205D377A000DB9EE /* RSTableViewCell.swift */; }; 24 | A2FC87A9205D672F000DB9EE /* RSEmptyDataView.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2FC87A8205D672F000DB9EE /* RSEmptyDataView.xib */; }; 25 | A2FC87AB205D6979000DB9EE /* RSEmptyDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2FC87AA205D6979000DB9EE /* RSEmptyDataView.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 865D11482136C129007D8C47 /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = ""; }; 30 | 865D114A2136C1D2007D8C47 /* ReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = ""; }; 31 | 865D114D2136C399007D8C47 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; 32 | 865D11502136C399007D8C47 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = ""; }; 33 | 865D11512136C399007D8C47 /* DataModelRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataModelRequest.swift; sourceTree = ""; }; 34 | 865D11522136C399007D8C47 /* JSONRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONRequest.swift; sourceTree = ""; }; 35 | 8698C9B82137CA9D00719582 /* RSPagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSPagination.swift; sourceTree = ""; }; 36 | 8698C9BA2137EE4900719582 /* RSSearchBarDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSearchBarDelegate.swift; sourceTree = ""; }; 37 | A294F7BD20530FD800195712 /* RSMasterTableViewKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RSMasterTableViewKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | A294F7C020530FD800195712 /* RSMasterTableViewKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RSMasterTableViewKit.h; sourceTree = ""; }; 39 | A294F7C120530FD800195712 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | A294F7D4205310AB00195712 /* RSTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSTableView.swift; sourceTree = ""; }; 41 | A2BE66DC225CCBD800ED4E43 /* Response.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Response.swift; sourceTree = ""; }; 42 | A2BE66DF225CCCB900ED4E43 /* ResponseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseError.swift; sourceTree = ""; }; 43 | A2FC87A0205D2910000DB9EE /* RSTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSTableViewDataSource.swift; sourceTree = ""; }; 44 | A2FC87A2205D377A000DB9EE /* RSTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSTableViewCell.swift; sourceTree = ""; }; 45 | A2FC87A8205D672F000DB9EE /* RSEmptyDataView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RSEmptyDataView.xib; sourceTree = ""; }; 46 | A2FC87AA205D6979000DB9EE /* RSEmptyDataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSEmptyDataView.swift; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | A294F7B920530FD800195712 /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | 865D11472136C0C9007D8C47 /* Reachability */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 865D11482136C129007D8C47 /* Reachability.swift */, 64 | 865D114A2136C1D2007D8C47 /* ReachabilityManager.swift */, 65 | ); 66 | path = Reachability; 67 | sourceTree = ""; 68 | }; 69 | 865D114C2136C399007D8C47 /* Networking */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 865D114D2136C399007D8C47 /* NetworkManager.swift */, 73 | 865D114F2136C399007D8C47 /* Request */, 74 | A2BE66DE225CCC3A00ED4E43 /* Response */, 75 | ); 76 | path = Networking; 77 | sourceTree = ""; 78 | }; 79 | 865D114F2136C399007D8C47 /* Request */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 865D11502136C399007D8C47 /* Request.swift */, 83 | 865D11522136C399007D8C47 /* JSONRequest.swift */, 84 | 865D11512136C399007D8C47 /* DataModelRequest.swift */, 85 | ); 86 | path = Request; 87 | sourceTree = ""; 88 | }; 89 | A294F7B320530FD800195712 = { 90 | isa = PBXGroup; 91 | children = ( 92 | A294F7BF20530FD800195712 /* RSMasterTableViewKit */, 93 | A294F7BE20530FD800195712 /* Products */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | A294F7BE20530FD800195712 /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | A294F7BD20530FD800195712 /* RSMasterTableViewKit.framework */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | A294F7BF20530FD800195712 /* RSMasterTableViewKit */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | A294F7C020530FD800195712 /* RSMasterTableViewKit.h */, 109 | A294F7D32053107300195712 /* RSTableView */, 110 | A2FC87A7205D6714000DB9EE /* RSEmptyDataSet */, 111 | 865D11472136C0C9007D8C47 /* Reachability */, 112 | 865D114C2136C399007D8C47 /* Networking */, 113 | A294F7C120530FD800195712 /* Info.plist */, 114 | ); 115 | path = RSMasterTableViewKit; 116 | sourceTree = ""; 117 | }; 118 | A294F7D32053107300195712 /* RSTableView */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | A2FC87A2205D377A000DB9EE /* RSTableViewCell.swift */, 122 | 8698C9B82137CA9D00719582 /* RSPagination.swift */, 123 | A2FC87A0205D2910000DB9EE /* RSTableViewDataSource.swift */, 124 | A294F7D4205310AB00195712 /* RSTableView.swift */, 125 | 8698C9BA2137EE4900719582 /* RSSearchBarDelegate.swift */, 126 | ); 127 | path = RSTableView; 128 | sourceTree = ""; 129 | }; 130 | A2BE66DE225CCC3A00ED4E43 /* Response */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | A2BE66DC225CCBD800ED4E43 /* Response.swift */, 134 | A2BE66DF225CCCB900ED4E43 /* ResponseError.swift */, 135 | ); 136 | path = Response; 137 | sourceTree = ""; 138 | }; 139 | A2FC87A7205D6714000DB9EE /* RSEmptyDataSet */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | A2FC87AA205D6979000DB9EE /* RSEmptyDataView.swift */, 143 | A2FC87A8205D672F000DB9EE /* RSEmptyDataView.xib */, 144 | ); 145 | path = RSEmptyDataSet; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXHeadersBuildPhase section */ 151 | A294F7BA20530FD800195712 /* Headers */ = { 152 | isa = PBXHeadersBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | A294F7C220530FD800195712 /* RSMasterTableViewKit.h in Headers */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXHeadersBuildPhase section */ 160 | 161 | /* Begin PBXNativeTarget section */ 162 | A294F7BC20530FD800195712 /* RSMasterTableViewKit */ = { 163 | isa = PBXNativeTarget; 164 | buildConfigurationList = A294F7C520530FD800195712 /* Build configuration list for PBXNativeTarget "RSMasterTableViewKit" */; 165 | buildPhases = ( 166 | A294F7B820530FD800195712 /* Sources */, 167 | A294F7B920530FD800195712 /* Frameworks */, 168 | A294F7BA20530FD800195712 /* Headers */, 169 | A294F7BB20530FD800195712 /* Resources */, 170 | ); 171 | buildRules = ( 172 | ); 173 | dependencies = ( 174 | ); 175 | name = RSMasterTableViewKit; 176 | productName = RSMasterTableViewKit; 177 | productReference = A294F7BD20530FD800195712 /* RSMasterTableViewKit.framework */; 178 | productType = "com.apple.product-type.framework"; 179 | }; 180 | /* End PBXNativeTarget section */ 181 | 182 | /* Begin PBXProject section */ 183 | A294F7B420530FD800195712 /* Project object */ = { 184 | isa = PBXProject; 185 | attributes = { 186 | LastUpgradeCheck = 0930; 187 | ORGANIZATIONNAME = "Rushi Sangani"; 188 | TargetAttributes = { 189 | A294F7BC20530FD800195712 = { 190 | CreatedOnToolsVersion = 9.2; 191 | LastSwiftMigration = 1020; 192 | ProvisioningStyle = Automatic; 193 | }; 194 | }; 195 | }; 196 | buildConfigurationList = A294F7B720530FD800195712 /* Build configuration list for PBXProject "RSMasterTableViewKit" */; 197 | compatibilityVersion = "Xcode 8.0"; 198 | developmentRegion = en; 199 | hasScannedForEncodings = 0; 200 | knownRegions = ( 201 | en, 202 | Base, 203 | ); 204 | mainGroup = A294F7B320530FD800195712; 205 | productRefGroup = A294F7BE20530FD800195712 /* Products */; 206 | projectDirPath = ""; 207 | projectRoot = ""; 208 | targets = ( 209 | A294F7BC20530FD800195712 /* RSMasterTableViewKit */, 210 | ); 211 | }; 212 | /* End PBXProject section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | A294F7BB20530FD800195712 /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | A2FC87A9205D672F000DB9EE /* RSEmptyDataView.xib in Resources */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXResourcesBuildPhase section */ 224 | 225 | /* Begin PBXSourcesBuildPhase section */ 226 | A294F7B820530FD800195712 /* Sources */ = { 227 | isa = PBXSourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 8698C9BB2137EE4900719582 /* RSSearchBarDelegate.swift in Sources */, 231 | 865D11552136C399007D8C47 /* Request.swift in Sources */, 232 | 865D11572136C399007D8C47 /* JSONRequest.swift in Sources */, 233 | A2FC87A3205D377A000DB9EE /* RSTableViewCell.swift in Sources */, 234 | A294F7D5205310AB00195712 /* RSTableView.swift in Sources */, 235 | A2FC87A1205D2910000DB9EE /* RSTableViewDataSource.swift in Sources */, 236 | 8698C9B92137CA9D00719582 /* RSPagination.swift in Sources */, 237 | 865D11532136C399007D8C47 /* NetworkManager.swift in Sources */, 238 | A2BE66DD225CCBD800ED4E43 /* Response.swift in Sources */, 239 | 865D11562136C399007D8C47 /* DataModelRequest.swift in Sources */, 240 | 865D114B2136C1D2007D8C47 /* ReachabilityManager.swift in Sources */, 241 | 865D11492136C129007D8C47 /* Reachability.swift in Sources */, 242 | A2FC87AB205D6979000DB9EE /* RSEmptyDataView.swift in Sources */, 243 | A2BE66E0225CCCB900ED4E43 /* ResponseError.swift in Sources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | /* End PBXSourcesBuildPhase section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | A294F7C320530FD800195712 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_COMMA = YES; 263 | CLANG_WARN_CONSTANT_CONVERSION = YES; 264 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 267 | CLANG_WARN_EMPTY_BODY = YES; 268 | CLANG_WARN_ENUM_CONVERSION = YES; 269 | CLANG_WARN_INFINITE_RECURSION = YES; 270 | CLANG_WARN_INT_CONVERSION = YES; 271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 276 | CLANG_WARN_STRICT_PROTOTYPES = YES; 277 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 278 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | CODE_SIGN_IDENTITY = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | CURRENT_PROJECT_VERSION = 1; 284 | DEBUG_INFORMATION_FORMAT = dwarf; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | ENABLE_TESTABILITY = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu11; 288 | GCC_DYNAMIC_NO_PIC = NO; 289 | GCC_NO_COMMON_BLOCKS = YES; 290 | GCC_OPTIMIZATION_LEVEL = 0; 291 | GCC_PREPROCESSOR_DEFINITIONS = ( 292 | "DEBUG=1", 293 | "$(inherited)", 294 | ); 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 297 | GCC_WARN_UNDECLARED_SELECTOR = YES; 298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 299 | GCC_WARN_UNUSED_FUNCTION = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 302 | MTL_ENABLE_DEBUG_INFO = YES; 303 | ONLY_ACTIVE_ARCH = YES; 304 | SDKROOT = iphoneos; 305 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 306 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 307 | VERSIONING_SYSTEM = "apple-generic"; 308 | VERSION_INFO_PREFIX = ""; 309 | }; 310 | name = Debug; 311 | }; 312 | A294F7C420530FD800195712 /* Release */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_ANALYZER_NONNULL = YES; 317 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 318 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 319 | CLANG_CXX_LIBRARY = "libc++"; 320 | CLANG_ENABLE_MODULES = YES; 321 | CLANG_ENABLE_OBJC_ARC = YES; 322 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_COMMA = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 327 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 328 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 335 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 337 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 338 | CLANG_WARN_STRICT_PROTOTYPES = YES; 339 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 340 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 341 | CLANG_WARN_UNREACHABLE_CODE = YES; 342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 343 | CODE_SIGN_IDENTITY = "iPhone Developer"; 344 | COPY_PHASE_STRIP = NO; 345 | CURRENT_PROJECT_VERSION = 1; 346 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 347 | ENABLE_NS_ASSERTIONS = NO; 348 | ENABLE_STRICT_OBJC_MSGSEND = YES; 349 | GCC_C_LANGUAGE_STANDARD = gnu11; 350 | GCC_NO_COMMON_BLOCKS = YES; 351 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 352 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 353 | GCC_WARN_UNDECLARED_SELECTOR = YES; 354 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 355 | GCC_WARN_UNUSED_FUNCTION = YES; 356 | GCC_WARN_UNUSED_VARIABLE = YES; 357 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 358 | MTL_ENABLE_DEBUG_INFO = NO; 359 | ONLY_ACTIVE_ARCH = YES; 360 | SDKROOT = iphoneos; 361 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 362 | VALIDATE_PRODUCT = YES; 363 | VERSIONING_SYSTEM = "apple-generic"; 364 | VERSION_INFO_PREFIX = ""; 365 | }; 366 | name = Release; 367 | }; 368 | A294F7C620530FD800195712 /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | CLANG_ENABLE_MODULES = YES; 372 | CODE_SIGN_IDENTITY = ""; 373 | CODE_SIGN_STYLE = Automatic; 374 | DEFINES_MODULE = YES; 375 | DEVELOPMENT_TEAM = ""; 376 | DYLIB_COMPATIBILITY_VERSION = 1; 377 | DYLIB_CURRENT_VERSION = 1; 378 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 379 | INFOPLIST_FILE = RSMasterTableViewKit/Info.plist; 380 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 381 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 383 | PRODUCT_BUNDLE_IDENTIFIER = com.rushi.RSMasterTableViewKit; 384 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 385 | SKIP_INSTALL = YES; 386 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 387 | SWIFT_VERSION = 5.0; 388 | TARGETED_DEVICE_FAMILY = "1,2"; 389 | }; 390 | name = Debug; 391 | }; 392 | A294F7C720530FD800195712 /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | CLANG_ENABLE_MODULES = YES; 396 | CODE_SIGN_IDENTITY = ""; 397 | CODE_SIGN_STYLE = Automatic; 398 | DEFINES_MODULE = YES; 399 | DEVELOPMENT_TEAM = ""; 400 | DYLIB_COMPATIBILITY_VERSION = 1; 401 | DYLIB_CURRENT_VERSION = 1; 402 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 403 | INFOPLIST_FILE = RSMasterTableViewKit/Info.plist; 404 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 405 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 406 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 407 | PRODUCT_BUNDLE_IDENTIFIER = com.rushi.RSMasterTableViewKit; 408 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 409 | SKIP_INSTALL = YES; 410 | SWIFT_VERSION = 5.0; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | }; 413 | name = Release; 414 | }; 415 | /* End XCBuildConfiguration section */ 416 | 417 | /* Begin XCConfigurationList section */ 418 | A294F7B720530FD800195712 /* Build configuration list for PBXProject "RSMasterTableViewKit" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | A294F7C320530FD800195712 /* Debug */, 422 | A294F7C420530FD800195712 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | A294F7C520530FD800195712 /* Build configuration list for PBXNativeTarget "RSMasterTableViewKit" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | A294F7C620530FD800195712 /* Debug */, 431 | A294F7C720530FD800195712 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | /* End XCConfigurationList section */ 437 | }; 438 | rootObject = A294F7B420530FD800195712 /* Project object */; 439 | } 440 | --------------------------------------------------------------------------------