├── ._Podfile ├── ._Info.plist ├── Pods ├── .DS_Store ├── ._.DS_Store ├── ._Pods.xcodeproj ├── Target Support Files │ ├── .DS_Store │ ├── ._.DS_Store │ ├── Pods-DemoProject │ │ ├── Pods-DemoProject-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-DemoProject-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-DemoProject.modulemap │ │ ├── Pods-DemoProject-dummy.m │ │ ├── Pods-DemoProject-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-DemoProject-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-DemoProject-umbrella.h │ │ ├── Pods-DemoProject-Info.plist │ │ ├── Pods-DemoProject.debug.xcconfig │ │ ├── Pods-DemoProject.release.xcconfig │ │ ├── Pods-DemoProject-acknowledgements.markdown │ │ ├── Pods-DemoProject-acknowledgements.plist │ │ └── Pods-DemoProject-frameworks.sh │ ├── Pods-DemoProject-DemoProjectUITests │ │ ├── Pods-DemoProject-DemoProjectUITests-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-DemoProject-DemoProjectUITests-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-DemoProject-DemoProjectUITests.modulemap │ │ ├── Pods-DemoProject-DemoProjectUITests-dummy.m │ │ ├── Pods-DemoProject-DemoProjectUITests-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-DemoProject-DemoProjectUITests-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-DemoProject-DemoProjectUITests-umbrella.h │ │ ├── Pods-DemoProject-DemoProjectUITests-Info.plist │ │ ├── Pods-DemoProject-DemoProjectUITests.debug.xcconfig │ │ ├── Pods-DemoProject-DemoProjectUITests.release.xcconfig │ │ ├── Pods-DemoProject-DemoProjectUITests-acknowledgements.markdown │ │ ├── Pods-DemoProject-DemoProjectUITests-acknowledgements.plist │ │ └── Pods-DemoProject-DemoProjectUITests-frameworks.sh │ ├── ReachabilitySwift │ │ ├── ReachabilitySwift.modulemap │ │ ├── ReachabilitySwift-dummy.m │ │ ├── ReachabilitySwift-prefix.pch │ │ ├── ReachabilitySwift-umbrella.h │ │ ├── ReachabilitySwift.debug.xcconfig │ │ ├── ReachabilitySwift.release.xcconfig │ │ └── ReachabilitySwift-Info.plist │ └── Pods-DemoProjectTests │ │ ├── Pods-DemoProjectTests.modulemap │ │ ├── Pods-DemoProjectTests-acknowledgements.markdown │ │ ├── Pods-DemoProjectTests-dummy.m │ │ ├── Pods-DemoProjectTests-umbrella.h │ │ ├── Pods-DemoProjectTests.debug.xcconfig │ │ ├── Pods-DemoProjectTests.release.xcconfig │ │ ├── Pods-DemoProjectTests-Info.plist │ │ └── Pods-DemoProjectTests-acknowledgements.plist ├── Manifest.lock ├── Pods.xcodeproj │ └── xcuserdata │ │ ├── ankushsharma.xcuserdatad │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ ├── Pods-DemoProject.xcscheme │ │ │ ├── ReachabilitySwift.xcscheme │ │ │ ├── Pods-DemoProjectTests.xcscheme │ │ │ └── Pods-DemoProject-DemoProjectUITests.xcscheme │ │ └── Ankush.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── ReachabilitySwift │ ├── LICENSE │ ├── README.md │ └── Sources │ └── Reachability.swift ├── DemoProject ├── .DS_Store ├── ._.DS_Store ├── Resources │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── left.imageset │ │ │ ├── left.png │ │ │ └── Contents.json │ │ ├── user.imageset │ │ │ ├── user.jpeg │ │ │ └── Contents.json │ │ ├── noData.imageset │ │ │ ├── noData.png │ │ │ └── Contents.json │ │ ├── documents.imageset │ │ │ ├── documents.png │ │ │ └── Contents.json │ │ ├── AccentColor.colorset │ │ │ ├── ._Contents.json │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── ._Loader.swift │ ├── ._Extension.swift │ ├── ._AppDelegate.swift │ ├── ._SceneDelegate.swift │ ├── Extension.swift │ ├── SceneDelegate.swift │ ├── Loader.swift │ └── AppDelegate.swift ├── Modals │ ├── ._Modals.swift │ ├── ._APIManager.swift │ ├── ._ViewModels.swift │ ├── ViewModels.swift │ ├── APIManager.swift │ └── Modals.swift ├── Cells │ ├── ._CustomCells.swift │ └── CustomCells.swift ├── Utilities │ ├── ._Utities.swift │ ├── ._Extensions.swift │ ├── ._ImageHelper.swift │ ├── ._Reachability.swift │ ├── Utities.swift │ ├── ImageHelper.swift │ ├── Reachability.swift │ └── Extensions.swift ├── CoreData │ ├── ._DBManager.swift │ ├── ._CoreDataStack.swift │ ├── ._DemoProject.xcdatamodeld │ ├── DemoProject.xcdatamodeld │ │ ├── ._DemoProject.xcdatamodel │ │ ├── .xccurrentversion │ │ └── DemoProject.xcdatamodel │ │ │ └── contents │ ├── CoreDataStack.swift │ └── DBManager.swift ├── Controllers │ ├── ._DataSource.swift │ ├── ._ListingVC.swift │ ├── ._ProfileVC.swift │ ├── DataSource.swift │ ├── ProfileVC.swift │ └── ListingVC.swift └── Views │ └── Base.lproj │ ├── ._Main.storyboard │ ├── ._LaunchScreen.storyboard │ └── LaunchScreen.storyboard ├── ._DemoProject.xcodeproj ├── ._DemoProject.xcworkspace ├── DemoProjectTests ├── ._DemoProjectTests.swift └── DemoProjectTests.swift ├── DemoProject.xcodeproj ├── ._project.xcworkspace ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── ankushsharma.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ ├── Ankush.xcuserdatad │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── ankushsharma.xcuserdatad │ │ ├── xcschemes │ │ └── xcschememanagement.plist │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist └── xcshareddata │ └── xcschemes │ └── DemoProject.xcscheme ├── DemoProjectUITests ├── ._DemoProjectUITests.swift ├── ._DemoProjectUITestsLaunchTests.swift ├── DemoProjectUITestsLaunchTests.swift └── DemoProjectUITests.swift ├── DemoProject.xcworkspace ├── xcuserdata │ ├── Ankush.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── ankushsharma.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Podfile.lock ├── Podfile ├── README.md └── Info.plist /._Podfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/._Podfile -------------------------------------------------------------------------------- /._Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/._Info.plist -------------------------------------------------------------------------------- /Pods/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/Pods/.DS_Store -------------------------------------------------------------------------------- /Pods/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/Pods/._.DS_Store -------------------------------------------------------------------------------- /DemoProject/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/.DS_Store -------------------------------------------------------------------------------- /Pods/._Pods.xcodeproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/Pods/._Pods.xcodeproj -------------------------------------------------------------------------------- /._DemoProject.xcodeproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/._DemoProject.xcodeproj -------------------------------------------------------------------------------- /DemoProject/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/._.DS_Store -------------------------------------------------------------------------------- /._DemoProject.xcworkspace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/._DemoProject.xcworkspace -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DemoProject/Modals/._Modals.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Modals/._Modals.swift -------------------------------------------------------------------------------- /DemoProject/Cells/._CustomCells.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Cells/._CustomCells.swift -------------------------------------------------------------------------------- /DemoProject/Modals/._APIManager.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Modals/._APIManager.swift -------------------------------------------------------------------------------- /DemoProject/Modals/._ViewModels.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Modals/._ViewModels.swift -------------------------------------------------------------------------------- /DemoProject/Resources/._Loader.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/._Loader.swift -------------------------------------------------------------------------------- /DemoProject/Utilities/._Utities.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Utilities/._Utities.swift -------------------------------------------------------------------------------- /Pods/Target Support Files/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/Pods/Target Support Files/.DS_Store -------------------------------------------------------------------------------- /Pods/Target Support Files/._.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/Pods/Target Support Files/._.DS_Store -------------------------------------------------------------------------------- /DemoProject/CoreData/._DBManager.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/CoreData/._DBManager.swift -------------------------------------------------------------------------------- /DemoProject/Resources/._Extension.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/._Extension.swift -------------------------------------------------------------------------------- /DemoProject/Controllers/._DataSource.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Controllers/._DataSource.swift -------------------------------------------------------------------------------- /DemoProject/Controllers/._ListingVC.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Controllers/._ListingVC.swift -------------------------------------------------------------------------------- /DemoProject/Controllers/._ProfileVC.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Controllers/._ProfileVC.swift -------------------------------------------------------------------------------- /DemoProject/CoreData/._CoreDataStack.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/CoreData/._CoreDataStack.swift -------------------------------------------------------------------------------- /DemoProject/Resources/._AppDelegate.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/._AppDelegate.swift -------------------------------------------------------------------------------- /DemoProject/Utilities/._Extensions.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Utilities/._Extensions.swift -------------------------------------------------------------------------------- /DemoProject/Utilities/._ImageHelper.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Utilities/._ImageHelper.swift -------------------------------------------------------------------------------- /DemoProject/Utilities/._Reachability.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Utilities/._Reachability.swift -------------------------------------------------------------------------------- /DemoProjectTests/._DemoProjectTests.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProjectTests/._DemoProjectTests.swift -------------------------------------------------------------------------------- /DemoProject.xcodeproj/._project.xcworkspace: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject.xcodeproj/._project.xcworkspace -------------------------------------------------------------------------------- /DemoProject/Resources/._SceneDelegate.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/._SceneDelegate.swift -------------------------------------------------------------------------------- /DemoProject/CoreData/._DemoProject.xcdatamodeld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/CoreData/._DemoProject.xcdatamodeld -------------------------------------------------------------------------------- /DemoProject/Views/Base.lproj/._Main.storyboard: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Views/Base.lproj/._Main.storyboard -------------------------------------------------------------------------------- /DemoProjectUITests/._DemoProjectUITests.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProjectUITests/._DemoProjectUITests.swift -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework -------------------------------------------------------------------------------- /DemoProject/Views/Base.lproj/._LaunchScreen.storyboard: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Views/Base.lproj/._LaunchScreen.storyboard -------------------------------------------------------------------------------- /DemoProjectUITests/._DemoProjectUITestsLaunchTests.swift: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProjectUITests/._DemoProjectUITestsLaunchTests.swift -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/left.imageset/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/Assets.xcassets/left.imageset/left.png -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/user.imageset/user.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/Assets.xcassets/user.imageset/user.jpeg -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/noData.imageset/noData.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/Assets.xcassets/noData.imageset/noData.png -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework -------------------------------------------------------------------------------- /DemoProject/CoreData/DemoProject.xcdatamodeld/._DemoProject.xcdatamodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/CoreData/DemoProject.xcdatamodeld/._DemoProject.xcdatamodel -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/documents.imageset/documents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/Assets.xcassets/documents.imageset/documents.png -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DemoProject { 2 | umbrella header "Pods-DemoProject-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift.modulemap: -------------------------------------------------------------------------------- 1 | framework module Reachability { 2 | umbrella header "ReachabilitySwift-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/AccentColor.colorset/._Contents.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject/Resources/Assets.xcassets/AccentColor.colorset/._Contents.json -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DemoProject : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DemoProject 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ReachabilitySwift : NSObject 3 | @end 4 | @implementation PodsDummy_ReachabilitySwift 5 | @end 6 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DemoProjectTests { 2 | umbrella header "Pods-DemoProjectTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /DemoProject.xcworkspace/xcuserdata/Ankush.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject.xcworkspace/xcuserdata/Ankush.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests-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-DemoProjectTests/Pods-DemoProjectTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DemoProjectTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DemoProjectTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework -------------------------------------------------------------------------------- /DemoProject.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /DemoProject.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/project.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ankush707/dynamicTableViewWithProtocol/HEAD/DemoProject.xcodeproj/project.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_DemoProject_DemoProjectUITests { 2 | umbrella header "Pods-DemoProject-DemoProjectUITests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_DemoProject_DemoProjectUITests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_DemoProject_DemoProjectUITests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework -------------------------------------------------------------------------------- /DemoProject.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /DemoProject.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DemoProject/CoreData/DemoProject.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | DemoProject.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ReachabilitySwift (5.0.0) 3 | 4 | DEPENDENCIES: 5 | - ReachabilitySwift 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - ReachabilitySwift 10 | 11 | SPEC CHECKSUMS: 12 | ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 13 | 14 | PODFILE CHECKSUM: ffac7fab375ef404a3c54684b55a5d11810e3d93 15 | 16 | COCOAPODS: 1.11.2 17 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ReachabilitySwift (5.0.0) 3 | 4 | DEPENDENCIES: 5 | - ReachabilitySwift 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - ReachabilitySwift 10 | 11 | SPEC CHECKSUMS: 12 | ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 13 | 14 | PODFILE CHECKSUM: ffac7fab375ef404a3c54684b55a5d11810e3d93 15 | 16 | COCOAPODS: 1.11.2 17 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/left.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "left.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift-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 ReachabilityVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ReachabilityVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/noData.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "noData.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/user.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "user.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-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_DemoProjectVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DemoProjectVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/documents.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "documents.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests-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_DemoProjectTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DemoProjectTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/xcuserdata/Ankush.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DemoProject.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'DemoProject' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for DemoProject 9 | pod 'ReachabilitySwift' 10 | 11 | target 'DemoProjectTests' do 12 | inherit! :search_paths 13 | # Pods for testing 14 | end 15 | 16 | target 'DemoProjectUITests' do 17 | # Pods for testing 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /DemoProject/Controllers/DataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataSource.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 13/04/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | protocol TableViewCompatible { 12 | 13 | func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> UITableViewCell 14 | 15 | } 16 | 17 | protocol Configurable { 18 | 19 | associatedtype T 20 | var model: T? { get set } 21 | func configureWithModel(_: T) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-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_DemoProject_DemoProjectUITestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_DemoProject_DemoProjectUITestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dynamicTableViewWithProtocol 2 | 3 | 4 | An Example of dynamic table view with the help of protocols; 5 | 6 | 1. Use of protocol for creating cells with the help of protocols. 7 | 2. Usage of Core data to save the data from API. 8 | 3. Saving images offline, once it is downloaded from web; image from offline storage is shown. 9 | 4. If internet is not avaliable then data is fetch from core data and offline image from file manager. 10 | 11 | ![1](https://user-images.githubusercontent.com/104753678/209680701-26dcaf45-7958-4e7b-8970-3b9170aed97e.jpeg) 12 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/project.xcworkspace/xcuserdata/ankushsharma.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | UseAppPreferences 7 | BuildSystemType 8 | Latest 9 | CustomBuildLocationType 10 | RelativeToDerivedData 11 | DerivedDataLocationStyle 12 | Default 13 | IssueFilterStyle 14 | ShowActiveSchemeOnly 15 | LiveSourceIssuesEnabled 16 | 17 | ShowSharedSchemesAutomaticallyEnabled 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /DemoProject/Resources/Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 13/04/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | extension UIImage { 12 | func inverseImage(cgResult: Bool) -> UIImage? { 13 | let coreImage = UIKit.CIImage(image: self) 14 | guard let filter = CIFilter(name: "CIColorInvert") else { return nil } 15 | filter.setValue(coreImage, forKey: kCIInputImageKey) 16 | guard let result = filter.value(forKey: kCIOutputImageKey) as? UIKit.CIImage else { return nil } 17 | if cgResult { // I've found that UIImage's that are based on CIImages don't work with a lot of calls properly 18 | return UIImage(cgImage: CIContext(options: nil).createCGImage(result, from: result.extent)!) 19 | } 20 | return UIImage(ciImage: result) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pods-DemoProject-DemoProjectUITests.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-DemoProject.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Pods-DemoProjectTests.xcscheme 18 | 19 | isShown 20 | 21 | 22 | ReachabilitySwift.xcscheme 23 | 24 | isShown 25 | 26 | 27 | 28 | SuppressBuildableAutocreation 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DemoProject.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 0257704B27EF99FC007CF775 16 | 17 | primary 18 | 19 | 20 | 0257706427EF99FE007CF775 21 | 22 | primary 23 | 24 | 25 | 0257706E27EF99FE007CF775 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DemoProject/Utilities/Utities.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utities.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | public class UtilityFunctions { 13 | 14 | 15 | public class func printToConsole(message : Any) { 16 | #if DEBUG 17 | print(message) 18 | #endif 19 | } 20 | 21 | public class func debugPrintToConsole(message : Any) { 22 | #if DEBUG 23 | debugPrint(message) 24 | #endif 25 | } 26 | 27 | class func showAlert(message : String?){ 28 | let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) 29 | alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil)) 30 | UIApplication.topViewController()?.present(alert, animated: true) 31 | } 32 | } 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Ankush.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Pods-DemoProject-DemoProjectUITests.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 4 11 | 12 | Pods-DemoProject.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 2 16 | 17 | Pods-DemoProjectTests.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 1 21 | 22 | ReachabilitySwift.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 3 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "SystemConfiguration" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReachabilitySwift 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Pods/Target Support Files/ReachabilitySwift/ReachabilitySwift.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "SystemConfiguration" 6 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 7 | PODS_BUILD_DIR = ${BUILD_DIR} 8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 9 | PODS_ROOT = ${SRCROOT} 10 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReachabilitySwift 11 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 12 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 13 | SKIP_INSTALL = YES 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /DemoProjectUITests/DemoProjectUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoProjectUITestsLaunchTests.swift 3 | // DemoProjectUITests 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import XCTest 9 | 10 | class DemoProjectUITestsLaunchTests: XCTestCase { 11 | 12 | override class var runsForEachTargetApplicationUIConfiguration: Bool { 13 | true 14 | } 15 | 16 | override func setUpWithError() throws { 17 | continueAfterFailure = false 18 | } 19 | 20 | func testLaunch() throws { 21 | let app = XCUIApplication() 22 | app.launch() 23 | 24 | // Insert steps here to perform after app launch but before taking a screenshot, 25 | // such as logging into a test account or navigating somewhere in the app 26 | 27 | let attachment = XCTAttachment(screenshot: app.screenshot()) 28 | attachment.name = "Launch Screen" 29 | attachment.lifetime = .keepAlways 30 | add(attachment) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-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/ReachabilitySwift/ReachabilitySwift-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 | 5.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProjectTests/Pods-DemoProjectTests-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-DemoProjectTests/Pods-DemoProjectTests-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 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-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 | -------------------------------------------------------------------------------- /DemoProjectTests/DemoProjectTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoProjectTests.swift 3 | // DemoProjectTests 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import XCTest 9 | @testable import DemoProject 10 | 11 | class DemoProjectTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | } 25 | 26 | func testPerformanceExample() throws { 27 | // This is an example of a performance test case. 28 | self.measure { 29 | // Put the code you want to measure the time of here. 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /DemoProject/Utilities/ImageHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageHelper.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | class ImageCache { 12 | private let cache = NSCache() 13 | private var observer: NSObjectProtocol? 14 | 15 | static let shared = ImageCache() 16 | 17 | private init() { 18 | 19 | observer = NotificationCenter.default.addObserver( 20 | forName: UIApplication.didReceiveMemoryWarningNotification, 21 | object: nil, 22 | queue: nil 23 | ) { [weak self] notification in 24 | self?.cache.removeAllObjects() 25 | } 26 | } 27 | 28 | deinit { 29 | NotificationCenter.default.removeObserver(observer!) 30 | } 31 | 32 | func image(forKey key: String) -> UIImage? { 33 | return cache.object(forKey: key as NSString) 34 | } 35 | 36 | func save(image: UIImage, forKey key: String) { 37 | cache.setObject(image, forKey: key as NSString) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Pods/ReachabilitySwift/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Ashley Mills 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/ReachabilitySwift/Reachability.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer/Library/Frameworks" '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift 8 | OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "Reachability" -framework "SystemConfiguration" 9 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 10 | PODS_BUILD_DIR = ${BUILD_DIR} 11 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 12 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 13 | PODS_ROOT = ${SRCROOT}/Pods 14 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 15 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 16 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ReachabilitySwift 5 | 6 | Copyright (c) 2016 Ashley Mills 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ReachabilitySwift 5 | 6 | Copyright (c) 2016 Ashley Mills 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /DemoProject/Utilities/Reachability.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reachability.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import Reachability 10 | import SystemConfiguration 11 | 12 | public class ReachabilityManager { 13 | 14 | class func isConnectedToNetwork() -> Bool { 15 | 16 | var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)) 17 | zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress)) 18 | zeroAddress.sin_family = sa_family_t(AF_INET) 19 | 20 | let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) { 21 | $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in 22 | SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress) 23 | } 24 | } 25 | 26 | var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0) 27 | if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false { 28 | return false 29 | } 30 | 31 | let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0 32 | let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0 33 | let ret = (isReachable && !needsConnection) 34 | 35 | return ret 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /DemoProjectUITests/DemoProjectUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoProjectUITests.swift 3 | // DemoProjectUITests 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import XCTest 9 | 10 | class DemoProjectUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | func testLaunchPerformance() throws { 35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { 36 | // This measures how long it takes to launch your application. 37 | measure(metrics: [XCTApplicationLaunchMetric()]) { 38 | XCUIApplication().launch() 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DemoProject/Modals/ViewModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModels.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 28/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | protocol ListingOutput: AnyObject { 12 | func updateView(user: [UserCore]?) 13 | } 14 | 15 | class ListingViewModel { 16 | 17 | weak var listingOutput: ListingOutput? 18 | private var fetchUserService: FetchUserService 19 | 20 | init(fetchUserService: FetchUserService) { 21 | self.fetchUserService = fetchUserService 22 | } 23 | 24 | func fetchUserList(since: Int) { 25 | fetchUserService.fetchUserListAPICall(compeletion: { [weak self] result in 26 | switch result { 27 | case .success(let user): 28 | self?.listingOutput?.updateView(user: user) 29 | case .failure: 30 | print("Failure") 31 | self?.listingOutput?.updateView(user: nil) 32 | } 33 | }, since: since) 34 | 35 | } 36 | 37 | } 38 | 39 | //detail View Models 40 | 41 | protocol DetailOutput: AnyObject { 42 | func updateView(user: UserDetail?) 43 | } 44 | 45 | class DetailViewModel { 46 | 47 | weak var detailOutput: DetailOutput? 48 | private var userDetailService: UserDetailService 49 | 50 | init(userDetailService: UserDetailService) { 51 | self.userDetailService = userDetailService 52 | } 53 | 54 | func fetchUserDeatil(username: String) { 55 | userDetailService.fetchUserDetailAPICall(compeletion: { [weak self] result in 56 | switch result { 57 | case .success(let user): 58 | self?.detailOutput?.updateView(user: user) 59 | case .failure: 60 | print("Failure") 61 | self?.detailOutput?.updateView(user: nil) 62 | } 63 | }, username: username) 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /DemoProject/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /DemoProject/Views/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DemoProject/CoreData/DemoProject.xcdatamodeld/DemoProject.xcdatamodel/contents: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/Pods-DemoProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/ReachabilitySwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/Pods-DemoProjectTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-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 | Copyright (c) 2016 Ashley Mills 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | ReachabilitySwift 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcschemes/Pods-DemoProject-DemoProjectUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-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 | Copyright (c) 2016 Ashley Mills 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | ReachabilitySwift 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /DemoProject/Cells/CustomCells.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCells.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | 13 | class NormalCell: UITableViewCell, Configurable { 14 | 15 | 16 | @IBOutlet weak var imgVw: UIImageView! 17 | @IBOutlet weak var nameLbl: UILabel! 18 | @IBOutlet weak var detailLbl: UILabel! 19 | 20 | var model: UserCore? 21 | 22 | func configureWithModel(_ model: UserCore) { 23 | self.model = model 24 | self.nameLbl.text = model.login?.uppercased() 25 | self.detailLbl.text = model.login 26 | self.imgVw.loadImageAsync(with: model.avatar_url, placeholder: UIImage.init(named: "user")) 27 | } 28 | 29 | 30 | } 31 | 32 | 33 | 34 | 35 | class NoteCell: UITableViewCell, Configurable { 36 | 37 | var notes:String? 38 | 39 | @IBOutlet weak var imgVw: UIImageView! 40 | @IBOutlet weak var nameLbl: UILabel! 41 | @IBOutlet weak var detailLbl: UILabel! 42 | @IBOutlet weak var noteBtn: UIButton! 43 | 44 | @IBAction func noteBtnAction(_ sender: Any) { 45 | UtilityFunctions.showAlert(message: self.notes) 46 | } 47 | 48 | var model: UserCore? 49 | 50 | func configureWithModel(_ model: UserCore) { 51 | self.model = model 52 | self.nameLbl.text = model.login?.uppercased() 53 | self.detailLbl.text = model.login 54 | self.imgVw.loadImageAsync(with: model.avatar_url, placeholder: UIImage.init(named: "user")) 55 | } 56 | } 57 | 58 | class InvertedCell: UITableViewCell, Configurable { 59 | 60 | 61 | var model: UserCore? 62 | 63 | func configureWithModel(_ model: UserCore) { 64 | self.model = model 65 | self.nameLbl.text = model.login?.uppercased() 66 | self.detailLbl.text = model.login 67 | self.imgVw.loadImageAsync(with: model.avatar_url, placeholder: UIImage.init(named: "user")) 68 | self.imgVw.image?.inverseImage(cgResult: true) 69 | if model.notes == "" { 70 | noteBtn.isHidden = true 71 | } else { 72 | noteBtn.isHidden = false 73 | } 74 | } 75 | 76 | 77 | @IBOutlet weak var imgVw: UIImageView! 78 | @IBOutlet weak var nameLbl: UILabel! 79 | @IBOutlet weak var detailLbl: UILabel! 80 | @IBOutlet weak var noteBtn: UIButton! 81 | 82 | @IBAction func noteBtnAction(_ sender: Any) { 83 | UtilityFunctions.showAlert(message: model?.notes) 84 | } 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /DemoProject/Resources/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 19 | guard let _ = (scene as? UIWindowScene) else { return } 20 | 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | 50 | // Save changes in the application's managed object context when the application transitions to the background. 51 | (UIApplication.shared.delegate as? AppDelegate)?.saveContext() 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /DemoProject/Modals/APIManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIManager.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 28/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | protocol UserDetailService { 12 | func fetchUserDetailAPICall(compeletion: @escaping (Result) -> Void,username: String) 13 | } 14 | 15 | protocol FetchUserService { 16 | func fetchUserListAPICall(compeletion: @escaping (Result<[UserCore], Error>) -> Void,since: Int) 17 | } 18 | 19 | class APIManager: FetchUserService, UserDetailService { 20 | 21 | func fetchUserListAPICall (compeletion: @escaping (Result<[UserCore], Error>) -> Void, since: Int) { 22 | 23 | var request = URLRequest(url: URL(string: "https://api.github.com/users?since=\(since)")!) 24 | request.httpMethod = "GET" 25 | //request.addValue("application/json", forHTTPHeaderField: "Content-Type") 26 | 27 | let session = URLSession.shared 28 | 29 | 30 | if !ReachabilityManager.isConnectedToNetwork() { 31 | UtilityFunctions.showAlert(message: "Internet is not available") 32 | return 33 | } 34 | 35 | let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in 36 | print(response!) 37 | do { 38 | let jsonDecoder = JSONDecoder() 39 | let responseModel = try jsonDecoder.decode([UserCore].self, from: data!) 40 | compeletion(.success(responseModel)) 41 | } catch { 42 | print("error") 43 | } 44 | }) 45 | 46 | task.resume() 47 | } 48 | 49 | func fetchUserDetailAPICall (compeletion: @escaping (Result) -> Void, username: String) { 50 | 51 | var request = URLRequest(url: URL(string: "https://api.github.com/users/\(username)")!) 52 | request.httpMethod = "GET" 53 | //request.addValue("application/json", forHTTPHeaderField: "Content-Type") 54 | 55 | let session = URLSession.shared 56 | 57 | 58 | if !ReachabilityManager.isConnectedToNetwork() { 59 | 60 | return 61 | } 62 | 63 | let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in 64 | print(response!) 65 | do { 66 | let jsonDecoder = JSONDecoder() 67 | let responseModel = try jsonDecoder.decode(UserDetail.self, from: data!) 68 | compeletion(.success(responseModel)) 69 | } catch { 70 | print("error") 71 | } 72 | }) 73 | 74 | task.resume() 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /DemoProject/CoreData/CoreDataStack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreData.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import CoreData 9 | import UIKit 10 | import Foundation 11 | 12 | open class CoreDataStack: NSObject { 13 | static let moduleName = "DemoProject" 14 | 15 | public func saveMainContext() { 16 | guard managedObjectContext.hasChanges || saveManagedObjectContext.hasChanges else { 17 | return 18 | } 19 | 20 | managedObjectContext.performAndWait() { 21 | do { 22 | try self.managedObjectContext.save() 23 | } catch { 24 | fatalError("Error saving main managed object context! \(error)") 25 | } 26 | } 27 | 28 | saveManagedObjectContext.perform() { 29 | do { 30 | try self.saveManagedObjectContext.save() 31 | } catch { 32 | fatalError("Error saving private managed object context! \(error)") 33 | } 34 | } 35 | } 36 | 37 | lazy var managedObjectModel: NSManagedObjectModel = { 38 | let modelURL = Bundle.main.url(forResource: CoreDataStack.moduleName, withExtension: "momd")! 39 | return NSManagedObjectModel(contentsOf: modelURL)! 40 | }() 41 | 42 | lazy var applicationDocumentsDirectory: URL = { 43 | return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! 44 | }() 45 | 46 | lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { 47 | let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) 48 | 49 | let persistentStoreURL = self.applicationDocumentsDirectory.appendingPathComponent("\(CoreDataStack.moduleName).sqlite") 50 | do { 51 | try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, 52 | configurationName: nil, 53 | at: persistentStoreURL, 54 | options: [NSMigratePersistentStoresAutomaticallyOption: true, 55 | NSInferMappingModelAutomaticallyOption: true]) 56 | } catch { 57 | fatalError("Persistent store error! \(error)") 58 | } 59 | 60 | return coordinator 61 | }() 62 | 63 | lazy var saveManagedObjectContext: NSManagedObjectContext = { 64 | let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 65 | moc.persistentStoreCoordinator = self.persistentStoreCoordinator 66 | return moc 67 | }() 68 | 69 | lazy var managedObjectContext: NSManagedObjectContext = { 70 | let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) 71 | managedObjectContext.parent = self.saveManagedObjectContext 72 | return managedObjectContext 73 | }() 74 | 75 | } 76 | -------------------------------------------------------------------------------- /DemoProject/Utilities/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | extension UIImageView { 13 | private static var taskKey = 0 14 | private static var urlKey = 0 15 | 16 | private var currentTask: URLSessionTask? { 17 | get { objc_getAssociatedObject(self, &UIImageView.taskKey) as? URLSessionTask } 18 | set { objc_setAssociatedObject(self, &UIImageView.taskKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } 19 | } 20 | 21 | private var currentURL: URL? { 22 | get { objc_getAssociatedObject(self, &UIImageView.urlKey) as? URL } 23 | set { objc_setAssociatedObject(self, &UIImageView.urlKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } 24 | } 25 | 26 | func loadImageAsync(with urlString: String?, placeholder: UIImage? = nil) { 27 | 28 | weak var oldTask = currentTask 29 | currentTask = nil 30 | oldTask?.cancel() 31 | 32 | self.image = placeholder 33 | 34 | guard let urlString = urlString else { return } 35 | 36 | if let cachedImage = ImageCache.shared.image(forKey: urlString) { 37 | self.image = cachedImage 38 | return 39 | } 40 | 41 | let url = URL(string: urlString)! 42 | currentURL = url 43 | let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in 44 | self?.currentTask = nil 45 | 46 | if let error = error { 47 | 48 | if (error as NSError).domain == NSURLErrorDomain && (error as NSError).code == NSURLErrorCancelled { 49 | return 50 | } 51 | 52 | print(error) 53 | return 54 | } 55 | 56 | guard let data = data, let downloadedImage = UIImage(data: data) else { 57 | print("unable to extract image") 58 | return 59 | } 60 | 61 | ImageCache.shared.save(image: downloadedImage, forKey: urlString) 62 | 63 | if url == self?.currentURL { 64 | DispatchQueue.main.async { 65 | self?.image = downloadedImage 66 | } 67 | } 68 | } 69 | 70 | currentTask = task 71 | task.resume() 72 | } 73 | } 74 | 75 | extension UIApplication { 76 | public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { 77 | if let nav = base as? UINavigationController { 78 | return topViewController(nav.visibleViewController) 79 | } 80 | if let tab = base as? UITabBarController { 81 | if let selected = tab.selectedViewController { 82 | return topViewController(selected) 83 | } 84 | } 85 | if let presented = base?.presentedViewController { 86 | return topViewController(presented) 87 | } 88 | return base 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /DemoProject/Controllers/ProfileVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProfileVC.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | 10 | import UIKit 11 | 12 | class ProfileVC: UIViewController, DetailOutput { 13 | func updateView(user: UserDetail?) { 14 | 15 | DispatchQueue.main.async { 16 | self.userDetailData = user 17 | self.setData() 18 | } 19 | 20 | 21 | } 22 | 23 | 24 | @IBOutlet weak var titleLbl: UILabel! 25 | @IBOutlet weak var imgVw: UIImageView! 26 | 27 | @IBOutlet weak var followersLbl: UILabel! 28 | @IBOutlet weak var followingLbl: UILabel! 29 | 30 | @IBOutlet weak var nameLbl: UILabel! 31 | @IBOutlet weak var companyLbl: UILabel! 32 | @IBOutlet weak var blogLbl: UILabel! 33 | 34 | @IBOutlet weak var noteLbl: UILabel! 35 | @IBOutlet weak var noteTxtVw: UITextView! 36 | 37 | private let userService: UserDetailService = APIManager() 38 | private var viewModal: DetailViewModel? 39 | var userData: UserCore? 40 | var userDetailData: UserDetail? 41 | 42 | override func viewDidLoad() { 43 | super.viewDidLoad() 44 | self.navigationController?.navigationBar.isHidden = true 45 | 46 | if let username = userData?.login { 47 | viewModal = DetailViewModel(userDetailService: userService) 48 | viewModal?.detailOutput = self 49 | viewModal?.fetchUserDeatil(username: username) 50 | } 51 | 52 | 53 | } 54 | 55 | private func setData() { 56 | 57 | self.titleLbl.text = userData?.login?.uppercased() 58 | self.imgVw.loadImageAsync(with: userDetailData?.avatar_url, placeholder: UIImage.init(named: "user")) 59 | 60 | if let followers = userDetailData?.followers { 61 | self.followersLbl.text = "Followers: \(followers)" 62 | } 63 | 64 | if let following = userDetailData?.following { 65 | self.followingLbl.text = "Following: \(following)" 66 | } 67 | 68 | if let name = userDetailData?.name { 69 | self.nameLbl.text = "Name: \(name)" 70 | } 71 | 72 | if let company = userDetailData?.company { 73 | self.companyLbl.text = "Company: \(company)" 74 | } 75 | 76 | if let blog = userDetailData?.blog { 77 | self.blogLbl.text = "Blog: \(blog)" 78 | } 79 | 80 | 81 | self.noteTxtVw.text = userData?.notes 82 | } 83 | 84 | @IBAction func backBtnAction(_ sender: Any) { 85 | self.navigationController?.popViewController(animated: true) 86 | } 87 | 88 | 89 | @IBAction func followersBtnAction(_ sender: Any) { 90 | guard let url = URL(string: userData?.followers_url ?? "") else { return } 91 | UIApplication.shared.open(url) 92 | } 93 | 94 | @IBAction func followingBtnAction(_ sender: Any) { 95 | guard let url = URL(string: userData?.following_url ?? "") else { return } 96 | UIApplication.shared.open(url) 97 | } 98 | 99 | 100 | @IBAction func saveBtnAction(_ sender: Any) { 101 | if self.noteTxtVw.text != "" { 102 | DBManager.sharedUserManager.updateAddons(user: self.userData,id: userData?.id, notes: self.noteTxtVw.text) 103 | } 104 | 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /DemoProject/Modals/Modals.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InitialVC.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | 12 | class UserCore: NSObject, Decodable, TableViewCompatible { 13 | var reuseIdentifier: String { 14 | return "NormalCell" 15 | } 16 | 17 | var login: String? 18 | var id: Int? 19 | 20 | var node_id: String? 21 | var avatar_url: String? 22 | var gravatar_id: String? 23 | var url: String? 24 | var html_url: String? 25 | var followers_url: String? 26 | var following_url: String? 27 | var gists_url: String? 28 | var starred_url: String? 29 | 30 | var subscriptions_url: String? 31 | var organizations_url: String? 32 | var repos_url: String? 33 | var events_url: String? 34 | var received_events_url: String? 35 | var type: String? 36 | var site_admin: Bool? 37 | var _notes: String? 38 | var notes: String? { return _notes ?? "" } 39 | 40 | public override init() { 41 | super.init() 42 | } 43 | 44 | 45 | func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> UITableViewCell { 46 | 47 | if indexPath.row % 4 != 3 { 48 | let cell = tableView.dequeueReusableCell(withIdentifier: Cells().reuseIdentifierInvertedCell, for: indexPath) as! InvertedCell 49 | cell.configureWithModel(self) 50 | return cell 51 | } 52 | 53 | if let notes = self.notes, !notes.isEmpty { 54 | let cell = tableView.dequeueReusableCell(withIdentifier: Cells().reuseIdentifierNoteCell, for: indexPath) as! NoteCell 55 | cell.configureWithModel(self) 56 | return cell 57 | } 58 | 59 | let cell = tableView.dequeueReusableCell(withIdentifier: Cells().reuseIdentifierNormalCell, for: indexPath) as! NormalCell 60 | cell.configureWithModel(self) 61 | return cell 62 | } 63 | } 64 | 65 | class UserDetail: NSObject, Decodable { 66 | var login: String? 67 | var id: Int? 68 | 69 | var node_id: String? 70 | var avatar_url: String? 71 | var gravatar_id: String? 72 | var url: String? 73 | var html_url: String? 74 | var followers_url: String? 75 | var following_url: String? 76 | var gists_url: String? 77 | var starred_url: String? 78 | 79 | var subscriptions_url: String? 80 | var organizations_url: String? 81 | var repos_url: String? 82 | var events_url: String? 83 | var received_events_url: String? 84 | var type: String? 85 | var site_admin: Bool? 86 | 87 | 88 | var name: String? 89 | var company: String? 90 | var blog: String? 91 | var location: String? 92 | var email: String? 93 | var hireable: String? 94 | 95 | var bio: String? 96 | var twitter_username: String? 97 | var public_repos: Int? 98 | var public_gists: Int? 99 | var followers: Int? 100 | var following: Int? 101 | var created_at: String? 102 | var updated_at: String? 103 | 104 | public override init() { 105 | super.init() 106 | } 107 | } 108 | 109 | 110 | struct Cells { 111 | var reuseIdentifierNormalCell = "NormalCell" 112 | var reuseIdentifierNoteCell = "NoteCell" 113 | var reuseIdentifierInvertedCell = "InvertedCell" 114 | } 115 | -------------------------------------------------------------------------------- /DemoProject/Resources/Loader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Loader.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | class LoadMoreActivityIndicator { 12 | 13 | private let spacingFromLastCell: CGFloat 14 | private let spacingFromLastCellWhenLoadMoreActionStart: CGFloat 15 | private weak var activityIndicatorView: UIActivityIndicatorView? 16 | private weak var scrollView: UIScrollView? 17 | 18 | private var defaultY: CGFloat { 19 | guard let height = scrollView?.contentSize.height else { return 0.0 } 20 | return height + spacingFromLastCell 21 | } 22 | 23 | deinit { activityIndicatorView?.removeFromSuperview() } 24 | 25 | init (scrollView: UIScrollView, spacingFromLastCell: CGFloat, spacingFromLastCellWhenLoadMoreActionStart: CGFloat) { 26 | self.scrollView = scrollView 27 | self.spacingFromLastCell = spacingFromLastCell 28 | self.spacingFromLastCellWhenLoadMoreActionStart = spacingFromLastCellWhenLoadMoreActionStart 29 | let size:CGFloat = 40 30 | let frame = CGRect(x: (scrollView.frame.width-size)/2, y: scrollView.contentSize.height + spacingFromLastCell, width: size, height: size) 31 | let activityIndicatorView = UIActivityIndicatorView(frame: frame) 32 | if #available(iOS 13.0, *) 33 | { 34 | activityIndicatorView.color = .label 35 | } 36 | else 37 | { 38 | activityIndicatorView.color = .black 39 | } 40 | activityIndicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin] 41 | activityIndicatorView.hidesWhenStopped = true 42 | scrollView.addSubview(activityIndicatorView) 43 | self.activityIndicatorView = activityIndicatorView 44 | } 45 | 46 | private var isHidden: Bool { 47 | guard let scrollView = scrollView else { return true } 48 | return scrollView.contentSize.height < scrollView.frame.size.height 49 | } 50 | 51 | func start(closure: (() -> Void)?) { 52 | guard let scrollView = scrollView, let activityIndicatorView = activityIndicatorView else { return } 53 | let offsetY = scrollView.contentOffset.y 54 | activityIndicatorView.isHidden = isHidden 55 | if !isHidden && offsetY >= 0 { 56 | let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height 57 | let offsetDelta = offsetY - contentDelta 58 | 59 | let newY = defaultY-offsetDelta 60 | if newY < scrollView.frame.height { 61 | activityIndicatorView.frame.origin.y = newY 62 | } else { 63 | if activityIndicatorView.frame.origin.y != defaultY { 64 | activityIndicatorView.frame.origin.y = defaultY 65 | } 66 | } 67 | 68 | if !activityIndicatorView.isAnimating { 69 | if offsetY > contentDelta && offsetDelta >= spacingFromLastCellWhenLoadMoreActionStart && !activityIndicatorView.isAnimating { 70 | activityIndicatorView.startAnimating() 71 | closure?() 72 | } 73 | } 74 | 75 | if scrollView.isDecelerating { 76 | if activityIndicatorView.isAnimating && scrollView.contentInset.bottom == 0 { 77 | UIView.animate(withDuration: 0.3) { [weak self] in 78 | if let bottom = self?.spacingFromLastCellWhenLoadMoreActionStart { 79 | scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: bottom, right: 0) 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | //a 88 | func stop(completion: (() -> Void)? = nil) { 89 | guard let scrollView = scrollView , let activityIndicatorView = activityIndicatorView else { return } 90 | let contentDelta = scrollView.contentSize.height - scrollView.frame.size.height 91 | let offsetDelta = scrollView.contentOffset.y - contentDelta 92 | if offsetDelta >= 0 { 93 | UIView.animate(withDuration: 0.3, animations: { 94 | scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 95 | }) { _ in completion?() } 96 | } else { 97 | scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 98 | completion?() 99 | } 100 | activityIndicatorView.stopAnimating() 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /DemoProject/Resources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import UIKit 9 | import CoreData 10 | import Reachability 11 | 12 | @main 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | 20 | let reachability = try! Reachability() 21 | 22 | reachability.whenReachable = { reachability in 23 | if reachability.connection == .wifi { 24 | print("Reachable via WiFi") 25 | } else { 26 | print("Reachable via Cellular") 27 | } 28 | } 29 | reachability.whenUnreachable = { _ in 30 | print("Not reachable") 31 | } 32 | 33 | do { 34 | try reachability.startNotifier() 35 | } catch { 36 | print("Unable to start notifier") 37 | } 38 | 39 | return true 40 | } 41 | 42 | // MARK: UISceneSession Lifecycle 43 | 44 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 45 | // Called when a new scene session is being created. 46 | // Use this method to select a configuration to create the new scene with. 47 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 48 | } 49 | 50 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 51 | // Called when the user discards a scene session. 52 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 53 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 54 | } 55 | 56 | // MARK: - Core Data stack 57 | 58 | lazy var persistentContainer: NSPersistentContainer = { 59 | /* 60 | The persistent container for the application. This implementation 61 | creates and returns a container, having loaded the store for the 62 | application to it. This property is optional since there are legitimate 63 | error conditions that could cause the creation of the store to fail. 64 | */ 65 | let container = NSPersistentContainer(name: "DemoProject") 66 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 67 | if let error = error as NSError? { 68 | // Replace this implementation with code to handle the error appropriately. 69 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 70 | 71 | /* 72 | Typical reasons for an error here include: 73 | * The parent directory does not exist, cannot be created, or disallows writing. 74 | * The persistent store is not accessible, due to permissions or data protection when the device is locked. 75 | * The device is out of space. 76 | * The store could not be migrated to the current model version. 77 | Check the error message to determine what the actual problem was. 78 | */ 79 | fatalError("Unresolved error \(error), \(error.userInfo)") 80 | } 81 | }) 82 | return container 83 | }() 84 | 85 | // MARK: - Core Data Saving support 86 | 87 | func saveContext () { 88 | let context = persistentContainer.viewContext 89 | if context.hasChanges { 90 | do { 91 | try context.save() 92 | } catch { 93 | // Replace this implementation with code to handle the error appropriately. 94 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 95 | let nserror = error as NSError 96 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 97 | } 98 | } 99 | } 100 | 101 | } 102 | 103 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/xcshareddata/xcschemes/DemoProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 73 | 75 | 81 | 82 | 83 | 84 | 90 | 92 | 98 | 99 | 100 | 101 | 103 | 104 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Pods/ReachabilitySwift/README.md: -------------------------------------------------------------------------------- 1 | # Reachability.swift 2 | 3 | Reachability.swift is a replacement for Apple's Reachability sample, re-written in Swift with closures. 4 | 5 | It is compatible with **iOS** (8.0 - 12.0), **OSX** (10.9 - 10.14) and **tvOS** (9.0 - 12.0) 6 | 7 | Inspired by https://github.com/tonymillion/Reachability 8 | 9 | ## Supporting **Reachability.swift** 10 | Keeping **Reachability.swift** up-to-date is a time consuming task. Making updates, reviewing pull requests, responding to issues and answering emails all take time. 11 | 12 | If you're an iOS developer who's looking for a quick and easy way to create App Store screenshots, please try out my app [Screenshot Producer](https://itunes.apple.com/app/apple-store/id1252374855?pt=215893&ct=reachability&mt=8)… 13 | 14 | Devices | Layout | Copy | Localize | Export       15 | :------:|:------:|:------:|:------:|:------: 16 | ![](http://is2.mzstatic.com/image/thumb/Purple118/v4/64/af/55/64af55bc-2ef0-691c-f5f3-4963685f7f63/source/552x414bb.jpg) | ![](http://is4.mzstatic.com/image/thumb/Purple128/v4/fb/4c/bd/fb4cbd2f-dd04-22ba-4fdf-5ac652693fb8/source/552x414bb.jpg) | ![](http://is1.mzstatic.com/image/thumb/Purple118/v4/5a/4f/cf/5a4fcfdf-ca04-0307-9f2e-83178e8ad90d/source/552x414bb.jpg) | ![](http://is4.mzstatic.com/image/thumb/Purple128/v4/17/ea/56/17ea562e-e045-96e7-fcac-cfaaf4f499fd/source/552x414bb.jpg) | ![](http://is4.mzstatic.com/image/thumb/Purple118/v4/59/9e/dd/599edd50-f05c-f413-8e88-e614731fd828/source/552x414bb.jpg) 17 | 18 | And don't forget to **★** the repo. This increases its visibility and encourages others to contribute. 19 | 20 | Thanks 21 | Ash 22 | 23 | 24 | ## Got a problem? 25 | 26 | Please read https://github.com/ashleymills/Reachability.swift/blob/master/CONTRIBUTING.md before raising an issue. 27 | 28 | ## Installation 29 | ### Manual 30 | Just drop the **Reachability.swift** file into your project. That's it! 31 | 32 | ### CocoaPods 33 | [CocoaPods][] is a dependency manager for Cocoa projects. To install Reachability.swift with CocoaPods: 34 | 35 | 1. Make sure CocoaPods is [installed][CocoaPods Installation]. 36 | 37 | 2. Update your Podfile to include the following: 38 | 39 | ``` ruby 40 | use_frameworks! 41 | pod 'ReachabilitySwift' 42 | ``` 43 | 44 | 3. Run `pod install`. 45 | 46 | [CocoaPods]: https://cocoapods.org 47 | [CocoaPods Installation]: https://guides.cocoapods.org/using/getting-started.html#getting-started 48 | 49 | 4. In your code import Reachability like so: 50 | `import Reachability` 51 | 52 | ### Carthage 53 | [Carthage][] is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 54 | To install Reachability.swift with Carthage: 55 | 56 | 1. Install Carthage via [Homebrew][] 57 | ```bash 58 | $ brew update 59 | $ brew install carthage 60 | ``` 61 | 62 | 2. Add `github "ashleymills/Reachability.swift"` to your Cartfile. 63 | 64 | 3. Run `carthage update`. 65 | 66 | 4. Drag `Reachability.framework` from the `Carthage/Build/iOS/` directory to the `Linked Frameworks and Libraries` section of your Xcode project’s `General` settings. 67 | 68 | 5. Add `$(SRCROOT)/Carthage/Build/iOS/Reachability.framework` to `Input Files` of Run Script Phase for Carthage. 69 | 70 | 6. In your code import Reachability like so: 71 | `import Reachability` 72 | 73 | 74 | [Carthage]: https://github.com/Carthage/Carthage 75 | [Homebrew]: http://brew.sh 76 | [Photo Flipper]: https://itunes.apple.com/app/apple-store/id749627884?pt=215893&ct=GitHubReachability&mt=8 77 | 78 | ## Example - closures 79 | 80 | NOTE: All closures are run on the **main queue**. 81 | 82 | ```swift 83 | //declare this property where it won't go out of scope relative to your listener 84 | let reachability = Reachability()! 85 | 86 | reachability.whenReachable = { reachability in 87 | if reachability.connection == .wifi { 88 | print("Reachable via WiFi") 89 | } else { 90 | print("Reachable via Cellular") 91 | } 92 | } 93 | reachability.whenUnreachable = { _ in 94 | print("Not reachable") 95 | } 96 | 97 | do { 98 | try reachability.startNotifier() 99 | } catch { 100 | print("Unable to start notifier") 101 | } 102 | ``` 103 | 104 | and for stopping notifications 105 | 106 | ```swift 107 | reachability.stopNotifier() 108 | ``` 109 | 110 | ## Example - notifications 111 | 112 | NOTE: All notifications are delivered on the **main queue**. 113 | 114 | ```swift 115 | //declare this property where it won't go out of scope relative to your listener 116 | let reachability = Reachability()! 117 | 118 | //declare this inside of viewWillAppear 119 | 120 | NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(note:)), name: .reachabilityChanged, object: reachability) 121 | do{ 122 | try reachability.startNotifier() 123 | }catch{ 124 | print("could not start reachability notifier") 125 | } 126 | ``` 127 | 128 | and 129 | 130 | ```swift 131 | @objc func reachabilityChanged(note: Notification) { 132 | 133 | let reachability = note.object as! Reachability 134 | 135 | switch reachability.connection { 136 | case .wifi: 137 | print("Reachable via WiFi") 138 | case .cellular: 139 | print("Reachable via Cellular") 140 | case .unavailable: 141 | print("Network not reachable") 142 | } 143 | } 144 | ``` 145 | 146 | and for stopping notifications 147 | 148 | ```swift 149 | reachability.stopNotifier() 150 | NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability) 151 | ``` 152 | 153 | ## Want to help? 154 | 155 | Got a bug fix, or a new feature? Create a pull request and go for it! 156 | 157 | ## Let me know! 158 | 159 | If you use **Reachability.swift**, please let me know about your app and I'll put a link [here…](https://github.com/ashleymills/Reachability.swift/wiki/Apps-using-Reachability.swift) and tell your friends! 160 | 161 | Cheers, 162 | Ash 163 | -------------------------------------------------------------------------------- /DemoProject.xcodeproj/xcuserdata/ankushsharma.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 21 | 22 | 23 | 25 | 37 | 38 | 39 | 41 | 53 | 54 | 55 | 57 | 69 | 70 | 71 | 73 | 85 | 86 | 87 | 89 | 101 | 102 | 103 | 105 | 117 | 118 | 119 | 121 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /DemoProject/Controllers/ListingVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListingVC.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import UIKit 9 | import Reachability 10 | 11 | 12 | class ListingVC: UIViewController, ListingOutput { 13 | 14 | //Outlets 15 | @IBOutlet weak private var noDataVw: UIView! { 16 | didSet { 17 | noDataVw.isHidden = true 18 | } 19 | } 20 | 21 | 22 | @IBOutlet private var searchbar: UISearchBar! 23 | @IBOutlet private weak var noDataImgVw: UIImageView! 24 | @IBOutlet private weak var tblVw: UITableView! 25 | 26 | //variables 27 | private var userArr: [UserCore]? 28 | private var searchedUserArr: [UserCore]? 29 | 30 | private let userService: FetchUserService = APIManager() 31 | private var viewModal : ListingViewModel? 32 | private var activityIndicator : LoadMoreActivityIndicator! 33 | 34 | private var isLoadingList: Bool = false 35 | let reachability = try! Reachability() 36 | var since: Int = 0 37 | var searchActive: Bool = false 38 | 39 | 40 | //MARK: - Viewdidload 41 | override func viewDidLoad() { 42 | super.viewDidLoad() 43 | //DBManager.sharedUserManager.cleanCart() 44 | tblVw.tableFooterView = UIView() 45 | activityIndicator = LoadMoreActivityIndicator(scrollView: tblVw, spacingFromLastCell: 10, spacingFromLastCellWhenLoadMoreActionStart: 60) 46 | viewModal = ListingViewModel(fetchUserService: userService) 47 | viewModal?.listingOutput = self 48 | self.tblVw.dataSource = self 49 | self.fetchOfflineUsers() 50 | 51 | } 52 | 53 | override func viewWillAppear(_ animated: Bool) { 54 | self.setNetworkChangeNotiHandler() 55 | } 56 | 57 | override func viewWillDisappear(_ animated: Bool) { 58 | self.stopNotif() 59 | } 60 | 61 | 62 | 63 | //MARK: - Reachability 64 | private func setNetworkChangeNotiHandler() { 65 | 66 | NotificationCenter.default.addObserver(self, selector: #selector(reachabilityChanged(note:)), name: .reachabilityChanged, object: reachability) 67 | do{ 68 | try reachability.startNotifier() 69 | }catch{ 70 | print("could not start reachability notifier") 71 | } 72 | } 73 | 74 | @objc func reachabilityChanged(note: Notification) { 75 | 76 | 77 | switch reachability.connection { 78 | case .wifi: 79 | if self.userArr?.count ?? 0 < 1 { 80 | self.fetchOfflineUsers() 81 | } 82 | case .cellular: 83 | if self.userArr?.count ?? 0 < 1 { 84 | self.fetchOfflineUsers() 85 | } 86 | case .unavailable: 87 | if self.userArr?.count ?? 0 < 1 { 88 | self.fetchOfflineUsers() 89 | } 90 | case .none: 91 | print("Nothing") 92 | } 93 | } 94 | 95 | private func stopNotif () { 96 | reachability.stopNotifier() 97 | NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability) 98 | } 99 | 100 | 101 | //MARK: - User data fetching 102 | private func fetchOfflineUsers() { 103 | DBManager.sharedUserManager.getUsersFromDatabase { userArr in 104 | self.userArr = userArr 105 | 106 | if self.userArr?.count ?? 0 < 1 { 107 | self.noDataVw.isHidden = false 108 | self.tblVw.isHidden = true 109 | 110 | if ReachabilityManager.isConnectedToNetwork() { 111 | 112 | self.getAllUsers(since: self.since) 113 | } 114 | } else { 115 | self.noDataVw.isHidden = true 116 | self.tblVw.isHidden = false 117 | self.since = self.userArr?.count ?? 0 - 1 118 | } 119 | 120 | self.tblVw.reloadData() 121 | } 122 | } 123 | 124 | private func getAllUsers(since: Int) { 125 | viewModal?.fetchUserList(since: since) 126 | } 127 | 128 | internal func updateView(user: [UserCore]?) { 129 | 130 | if userArr?.count ?? 0 > 0 { 131 | self.userArr?.append(contentsOf: user!) 132 | } else { 133 | self.userArr = user 134 | } 135 | 136 | DispatchQueue.main.async { 137 | self.tblVw.reloadData() 138 | if self.userArr?.count ?? 0 < 1 { 139 | self.noDataVw.isHidden = false 140 | self.tblVw.isHidden = true 141 | } else { 142 | self.noDataVw.isHidden = true 143 | self.tblVw.isHidden = false 144 | } 145 | } 146 | DBManager.sharedUserManager.saveUsersToCoreData(users: user) 147 | DispatchQueue.main.async { [weak self] in 148 | self?.isLoadingList = false 149 | self?.activityIndicator.stop() 150 | } 151 | } 152 | } 153 | 154 | 155 | // Table view logic 156 | extension ListingVC : UITableViewDelegate, UITableViewDataSource { 157 | 158 | 159 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 160 | if searchActive { 161 | return searchedUserArr?.count ?? 0 162 | } 163 | return userArr?.count ?? 0 164 | } 165 | 166 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 167 | 168 | if searchActive { 169 | return (self.searchedUserArr?[indexPath.row].cellForTableView(tableView: tableView, atIndexPath: indexPath))! 170 | } 171 | 172 | return (self.userArr?[indexPath.row].cellForTableView(tableView: tableView, atIndexPath: indexPath))! 173 | 174 | } 175 | 176 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 177 | if !ReachabilityManager.isConnectedToNetwork() { 178 | UtilityFunctions.showAlert(message: "Internet is not available") 179 | return 180 | } 181 | 182 | let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ProfileVC") as? ProfileVC 183 | if searchActive { 184 | vc?.userData = self.searchedUserArr?[indexPath.row] 185 | } else { 186 | vc?.userData = self.userArr?[indexPath.row] 187 | } 188 | 189 | self.navigationController?.pushViewController(vc!, animated: true) 190 | } 191 | 192 | } 193 | 194 | 195 | // Scrolling and adding data to listing logic 196 | 197 | extension ListingVC { 198 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 199 | 200 | if (((scrollView.contentOffset.y + scrollView.frame.size.height) > scrollView.contentSize.height ) && !self.isLoadingList && ReachabilityManager.isConnectedToNetwork() && !searchActive) { 201 | activityIndicator.start { 202 | DispatchQueue.main.async { 203 | 204 | self.isLoadingList = true 205 | 206 | self.since = self.userArr?.count ?? 0 - 1 207 | 208 | self.getAllUsers(since: self.since) 209 | 210 | } 211 | } 212 | } 213 | } 214 | } 215 | 216 | 217 | // Searching logic 218 | extension ListingVC: UISearchBarDelegate { 219 | 220 | func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { 221 | 222 | if searchText == "" { 223 | searchActive = false 224 | } else { 225 | searchActive = true 226 | } 227 | searchedUserArr = [] 228 | searchedUserArr = userArr?.filter({ user in 229 | 230 | if let text = user.login { 231 | return text.lowercased().contains(searchText.lowercased()) 232 | } 233 | return false 234 | 235 | }) 236 | 237 | DispatchQueue.main.async { 238 | self.tblVw.reloadData() 239 | } 240 | 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject/Pods-DemoProject-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | BCSYMBOLMAP_DIR="BCSymbolMaps" 23 | 24 | 25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 28 | 29 | # Copies and strips a vendored framework 30 | install_framework() 31 | { 32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 33 | local source="${BUILT_PRODUCTS_DIR}/$1" 34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 36 | elif [ -r "$1" ]; then 37 | local source="$1" 38 | fi 39 | 40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 41 | 42 | if [ -L "${source}" ]; then 43 | echo "Symlinked..." 44 | source="$(readlink "${source}")" 45 | fi 46 | 47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then 48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied 49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do 50 | echo "Installing $f" 51 | install_bcsymbolmap "$f" "$destination" 52 | rm "$f" 53 | done 54 | rmdir "${source}/${BCSYMBOLMAP_DIR}" 55 | fi 56 | 57 | # Use filter instead of exclude so missing patterns don't throw errors. 58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 60 | 61 | local basename 62 | basename="$(basename -s .framework "$1")" 63 | binary="${destination}/${basename}.framework/${basename}" 64 | 65 | if ! [ -r "$binary" ]; then 66 | binary="${destination}/${basename}" 67 | elif [ -L "${binary}" ]; then 68 | echo "Destination binary is symlinked..." 69 | dirname="$(dirname "${binary}")" 70 | binary="${dirname}/$(readlink "${binary}")" 71 | fi 72 | 73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 75 | strip_invalid_archs "$binary" 76 | fi 77 | 78 | # Resign the code if required by the build settings to avoid unstable apps 79 | code_sign_if_enabled "${destination}/$(basename "$1")" 80 | 81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 83 | local swift_runtime_libs 84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 85 | for lib in $swift_runtime_libs; do 86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 88 | code_sign_if_enabled "${destination}/${lib}" 89 | done 90 | fi 91 | } 92 | # Copies and strips a vendored dSYM 93 | install_dsym() { 94 | local source="$1" 95 | warn_missing_arch=${2:-true} 96 | if [ -r "$source" ]; then 97 | # Copy the dSYM into the targets temp dir. 98 | 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}\"" 99 | 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}" 100 | 101 | local basename 102 | basename="$(basename -s .dSYM "$source")" 103 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 105 | 106 | # Strip invalid architectures from the dSYM. 107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 108 | strip_invalid_archs "$binary" "$warn_missing_arch" 109 | fi 110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then 111 | # Move the stripped file into its final destination. 112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 114 | else 115 | # 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. 116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}" 117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 118 | fi 119 | fi 120 | } 121 | 122 | # Used as a return value for each invocation of `strip_invalid_archs` function. 123 | STRIP_BINARY_RETVAL=0 124 | 125 | # Strip invalid architectures 126 | strip_invalid_archs() { 127 | binary="$1" 128 | warn_missing_arch=${2:-true} 129 | # Get architectures for current target binary 130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 131 | # Intersect them with the architectures we are building for 132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 133 | # If there are no archs supported by this binary then warn the user 134 | if [[ -z "$intersected_archs" ]]; then 135 | if [[ "$warn_missing_arch" == "true" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | fi 138 | STRIP_BINARY_RETVAL=1 139 | return 140 | fi 141 | stripped="" 142 | for arch in $binary_archs; do 143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 144 | # Strip non-valid architectures in-place 145 | lipo -remove "$arch" -output "$binary" "$binary" 146 | stripped="$stripped $arch" 147 | fi 148 | done 149 | if [[ "$stripped" ]]; then 150 | echo "Stripped $binary of architectures:$stripped" 151 | fi 152 | STRIP_BINARY_RETVAL=0 153 | } 154 | 155 | # Copies the bcsymbolmap files of a vendored framework 156 | install_bcsymbolmap() { 157 | local bcsymbolmap_path="$1" 158 | local destination="${BUILT_PRODUCTS_DIR}" 159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 161 | } 162 | 163 | # Signs a framework with the provided identity 164 | code_sign_if_enabled() { 165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 166 | # Use the current code_sign_identity 167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 169 | 170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 171 | code_sign_cmd="$code_sign_cmd &" 172 | fi 173 | echo "$code_sign_cmd" 174 | eval "$code_sign_cmd" 175 | fi 176 | } 177 | 178 | if [[ "$CONFIGURATION" == "Debug" ]]; then 179 | install_framework "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework" 180 | fi 181 | if [[ "$CONFIGURATION" == "Release" ]]; then 182 | install_framework "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework" 183 | fi 184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 185 | wait 186 | fi 187 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-DemoProject-DemoProjectUITests/Pods-DemoProject-DemoProjectUITests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | BCSYMBOLMAP_DIR="BCSymbolMaps" 23 | 24 | 25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 28 | 29 | # Copies and strips a vendored framework 30 | install_framework() 31 | { 32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 33 | local source="${BUILT_PRODUCTS_DIR}/$1" 34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 36 | elif [ -r "$1" ]; then 37 | local source="$1" 38 | fi 39 | 40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 41 | 42 | if [ -L "${source}" ]; then 43 | echo "Symlinked..." 44 | source="$(readlink "${source}")" 45 | fi 46 | 47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then 48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied 49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do 50 | echo "Installing $f" 51 | install_bcsymbolmap "$f" "$destination" 52 | rm "$f" 53 | done 54 | rmdir "${source}/${BCSYMBOLMAP_DIR}" 55 | fi 56 | 57 | # Use filter instead of exclude so missing patterns don't throw errors. 58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 60 | 61 | local basename 62 | basename="$(basename -s .framework "$1")" 63 | binary="${destination}/${basename}.framework/${basename}" 64 | 65 | if ! [ -r "$binary" ]; then 66 | binary="${destination}/${basename}" 67 | elif [ -L "${binary}" ]; then 68 | echo "Destination binary is symlinked..." 69 | dirname="$(dirname "${binary}")" 70 | binary="${dirname}/$(readlink "${binary}")" 71 | fi 72 | 73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 75 | strip_invalid_archs "$binary" 76 | fi 77 | 78 | # Resign the code if required by the build settings to avoid unstable apps 79 | code_sign_if_enabled "${destination}/$(basename "$1")" 80 | 81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 83 | local swift_runtime_libs 84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 85 | for lib in $swift_runtime_libs; do 86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 88 | code_sign_if_enabled "${destination}/${lib}" 89 | done 90 | fi 91 | } 92 | # Copies and strips a vendored dSYM 93 | install_dsym() { 94 | local source="$1" 95 | warn_missing_arch=${2:-true} 96 | if [ -r "$source" ]; then 97 | # Copy the dSYM into the targets temp dir. 98 | 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}\"" 99 | 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}" 100 | 101 | local basename 102 | basename="$(basename -s .dSYM "$source")" 103 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 105 | 106 | # Strip invalid architectures from the dSYM. 107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 108 | strip_invalid_archs "$binary" "$warn_missing_arch" 109 | fi 110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then 111 | # Move the stripped file into its final destination. 112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 114 | else 115 | # 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. 116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}" 117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 118 | fi 119 | fi 120 | } 121 | 122 | # Used as a return value for each invocation of `strip_invalid_archs` function. 123 | STRIP_BINARY_RETVAL=0 124 | 125 | # Strip invalid architectures 126 | strip_invalid_archs() { 127 | binary="$1" 128 | warn_missing_arch=${2:-true} 129 | # Get architectures for current target binary 130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 131 | # Intersect them with the architectures we are building for 132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 133 | # If there are no archs supported by this binary then warn the user 134 | if [[ -z "$intersected_archs" ]]; then 135 | if [[ "$warn_missing_arch" == "true" ]]; then 136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 137 | fi 138 | STRIP_BINARY_RETVAL=1 139 | return 140 | fi 141 | stripped="" 142 | for arch in $binary_archs; do 143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 144 | # Strip non-valid architectures in-place 145 | lipo -remove "$arch" -output "$binary" "$binary" 146 | stripped="$stripped $arch" 147 | fi 148 | done 149 | if [[ "$stripped" ]]; then 150 | echo "Stripped $binary of architectures:$stripped" 151 | fi 152 | STRIP_BINARY_RETVAL=0 153 | } 154 | 155 | # Copies the bcsymbolmap files of a vendored framework 156 | install_bcsymbolmap() { 157 | local bcsymbolmap_path="$1" 158 | local destination="${BUILT_PRODUCTS_DIR}" 159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 161 | } 162 | 163 | # Signs a framework with the provided identity 164 | code_sign_if_enabled() { 165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 166 | # Use the current code_sign_identity 167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 169 | 170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 171 | code_sign_cmd="$code_sign_cmd &" 172 | fi 173 | echo "$code_sign_cmd" 174 | eval "$code_sign_cmd" 175 | fi 176 | } 177 | 178 | if [[ "$CONFIGURATION" == "Debug" ]]; then 179 | install_framework "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework" 180 | fi 181 | if [[ "$CONFIGURATION" == "Release" ]]; then 182 | install_framework "${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework" 183 | fi 184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 185 | wait 186 | fi 187 | -------------------------------------------------------------------------------- /DemoProject/CoreData/DBManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DBManager.swift 3 | // DemoProject 4 | // 5 | // Created by Ankush Sharma on 27/03/22. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | import CoreData 11 | 12 | 13 | public enum UserKeys : String { 14 | case login = "login" 15 | case id = "id" 16 | case node_id = "node_id" 17 | case avatar_url = "avatar_url" 18 | case gravatar_id = "gravatar_id" 19 | case url = "url" 20 | case html_url = "html_url" 21 | case followers_url = "followers_url" 22 | case following_url = "following_url" 23 | case gists_url = "gists_url" 24 | case starred_url = "starred_url" 25 | case subscriptions_url = "subscriptions_url" 26 | case organizations_url = "organizations_url" 27 | case repos_url = "repos_url" 28 | case events_url = "events_url" 29 | case received_events_url = "received_events_url" 30 | case type = "type" 31 | case site_admin = "site_admin" 32 | case notes = "notes" 33 | } 34 | 35 | 36 | 37 | enum CoreDataEntity : String { 38 | case Users = "Users" 39 | } 40 | 41 | typealias UsersCompletionBlock = ([UserCore]?) -> () 42 | 43 | open class DBManager : NSObject { 44 | public let coreDataStackObj = CoreDataStack() 45 | 46 | public var coreDataStack : CoreDataStack{ 47 | get{ 48 | return coreDataStackObj 49 | } 50 | } 51 | 52 | static var sharedUserManager = DBManager() 53 | 54 | 55 | func getUsersFromDatabase(result : @escaping UsersCompletionBlock){ 56 | 57 | let fetchRequest = NSFetchRequest(entityName: CoreDataEntity.Users.rawValue) 58 | 59 | coreDataStack.managedObjectContext.perform { 60 | 61 | do { 62 | weak var weakSelf = self 63 | guard let results = try weakSelf?.coreDataStack.managedObjectContext.fetch(fetchRequest) as? [NSManagedObject], let cartArray = weakSelf?.convertManagedObjectArrayToUserArray(arrManagedObject: results) else { return } 64 | 65 | result(cartArray) 66 | }catch let error { 67 | UtilityFunctions.printToConsole(message: error) 68 | } 69 | } 70 | } 71 | 72 | func isExist(id: Int) -> Bool { 73 | let fetchRequest = NSFetchRequest(entityName: CoreDataEntity.Users.rawValue) 74 | fetchRequest.predicate = NSPredicate(format: "id = %d", argumentArray: [id]) 75 | 76 | let res = try! coreDataStack.managedObjectContext.fetch(fetchRequest) 77 | return res.count > 0 ? true : false 78 | } 79 | 80 | func convertManagedObjectArrayToUserArray(arrManagedObject : [NSManagedObject]) -> [UserCore]{ 81 | 82 | var arrUsers : [UserCore] = [] 83 | for mc in arrManagedObject { 84 | let user = UserCore() 85 | user.login = mc.value(forKey: UserKeys.login.rawValue) as? String 86 | user.id = mc.value(forKey: UserKeys.id.rawValue) as? Int 87 | user.node_id = mc.value(forKey: UserKeys.node_id.rawValue) as? String 88 | user.avatar_url = mc.value(forKey: UserKeys.avatar_url.rawValue) as? String 89 | user.gravatar_id = mc.value(forKey: UserKeys.gravatar_id.rawValue) as? String 90 | user.url = mc.value(forKey: UserKeys.url.rawValue) as? String 91 | user.html_url = mc.value(forKey: UserKeys.html_url.rawValue) as? String 92 | user.followers_url = mc.value(forKey: UserKeys.followers_url.rawValue) as? String 93 | user.following_url = mc.value(forKey: UserKeys.following_url.rawValue) as? String 94 | user.gists_url = mc.value(forKey: UserKeys.gists_url.rawValue) as? String 95 | user.starred_url = mc.value(forKey: UserKeys.starred_url.rawValue) as? String 96 | user.subscriptions_url = mc.value(forKey: UserKeys.subscriptions_url.rawValue) as? String 97 | user.organizations_url = mc.value(forKey: UserKeys.organizations_url.rawValue) as? String 98 | user.repos_url = mc.value(forKey: UserKeys.repos_url.rawValue) as? String 99 | user.events_url = mc.value(forKey: UserKeys.events_url.rawValue) as? String 100 | user.received_events_url = mc.value(forKey: UserKeys.received_events_url.rawValue) as? String 101 | user.type = mc.value(forKey: UserKeys.type.rawValue) as? String 102 | user.site_admin = mc.value(forKey: UserKeys.site_admin.rawValue) as? Bool 103 | user._notes = mc.value(forKey: UserKeys.notes.rawValue) as? String 104 | arrUsers.append(user) 105 | 106 | } 107 | 108 | return arrUsers 109 | } 110 | 111 | 112 | func saveUsersToCoreData(users : [UserCore]?) { 113 | 114 | guard let arrusers = users else { return } 115 | 116 | for user in arrusers { 117 | if !self.isExist(id: user.id!) { 118 | self.saveUserToDB(entityName: CoreDataEntity.Users.rawValue, user: user) 119 | } 120 | 121 | } 122 | } 123 | 124 | func saveUserToDB(entityName : String,user : UserCore?){ 125 | 126 | guard let entity = NSEntityDescription.entity(forEntityName: entityName, in: (coreDataStack.managedObjectContext)),let tempMessage = user else { 127 | fatalError("Could not find entity descriptions!") 128 | } 129 | 130 | coreDataStack.managedObjectContext.mergePolicy = NSErrorMergePolicy 131 | let currentMessage = NSManagedObject(entity: entity, insertInto: coreDataStack.managedObjectContext) 132 | currentMessage.setValue(tempMessage.login, forKey: UserKeys.login.rawValue) 133 | currentMessage.setValue(tempMessage.id, forKey: UserKeys.id.rawValue) 134 | currentMessage.setValue(tempMessage.node_id, forKey: UserKeys.node_id.rawValue) 135 | currentMessage.setValue(tempMessage.avatar_url, forKey: UserKeys.avatar_url.rawValue) 136 | currentMessage.setValue(tempMessage.gravatar_id, forKey: UserKeys.gravatar_id.rawValue) 137 | 138 | currentMessage.setValue(tempMessage.url, forKey: UserKeys.url.rawValue) 139 | currentMessage.setValue(tempMessage.html_url, forKey: UserKeys.html_url.rawValue) 140 | currentMessage.setValue(tempMessage.followers_url, forKey: UserKeys.followers_url.rawValue) 141 | currentMessage.setValue(tempMessage.following_url, forKey: UserKeys.following_url.rawValue) 142 | currentMessage.setValue(tempMessage.gists_url, forKey: UserKeys.gists_url.rawValue) 143 | currentMessage.setValue(tempMessage.starred_url, forKey: UserKeys.starred_url.rawValue) 144 | currentMessage.setValue(tempMessage.subscriptions_url, forKey: UserKeys.subscriptions_url.rawValue) 145 | currentMessage.setValue(tempMessage.organizations_url, forKey: UserKeys.organizations_url.rawValue) 146 | currentMessage.setValue(tempMessage.repos_url, forKey: UserKeys.repos_url.rawValue) 147 | currentMessage.setValue(tempMessage.events_url, forKey: UserKeys.events_url.rawValue) 148 | currentMessage.setValue(tempMessage.received_events_url, forKey: UserKeys.received_events_url.rawValue) 149 | currentMessage.setValue(tempMessage.type, forKey: UserKeys.type.rawValue) 150 | currentMessage.setValue(tempMessage.site_admin, forKey: UserKeys.site_admin.rawValue) 151 | currentMessage.setValue(tempMessage.notes, forKey: UserKeys.notes.rawValue) 152 | 153 | coreDataStack.saveMainContext() 154 | } 155 | 156 | func cleanCart() { 157 | 158 | let dbNames = [CoreDataEntity.Users.rawValue] 159 | dbNames.forEach { (dBName) in 160 | self.removeDataFromTable(tableName: dBName) 161 | } 162 | } 163 | 164 | func removeDataFromTable(tableName : String) { 165 | 166 | let managedContext = coreDataStack.managedObjectContext 167 | let fetchRequest = NSFetchRequest(entityName: tableName) 168 | fetchRequest.returnsObjectsAsFaults = false 169 | 170 | do { 171 | let results = try managedContext.fetch(fetchRequest) 172 | for managedObject in results 173 | { 174 | let managedObjectData:NSManagedObject = managedObject as! NSManagedObject 175 | managedContext.delete(managedObjectData) 176 | } 177 | self.coreDataStack.saveMainContext() 178 | 179 | } catch let error as NSError { 180 | UtilityFunctions.printToConsole(message: "delete failed-- \(error)") 181 | } 182 | } 183 | 184 | func updateAddons(user : UserCore? ,id: Int?,notes: String?) { 185 | 186 | let managedContext = coreDataStack.managedObjectContext 187 | 188 | let fetchRequest = NSFetchRequest(entityName: CoreDataEntity.Users.rawValue) 189 | fetchRequest.predicate = NSPredicate(format: "id = %d", argumentArray: [id]) 190 | 191 | do { 192 | let results = 193 | try managedContext.fetch(fetchRequest) 194 | let objectUpdate = results[0] as! NSManagedObject 195 | 196 | guard let currentProduct = user else { 197 | return 198 | } 199 | 200 | objectUpdate.setValue(currentProduct.login, forKey: UserKeys.login.rawValue) 201 | objectUpdate.setValue(currentProduct.id, forKey: UserKeys.id.rawValue) 202 | objectUpdate.setValue(currentProduct.node_id, forKey: UserKeys.node_id.rawValue) 203 | objectUpdate.setValue(currentProduct.avatar_url, forKey: UserKeys.avatar_url.rawValue) 204 | objectUpdate.setValue(currentProduct.gravatar_id, forKey: UserKeys.gravatar_id.rawValue) 205 | 206 | objectUpdate.setValue(currentProduct.url, forKey: UserKeys.url.rawValue) 207 | objectUpdate.setValue(currentProduct.html_url, forKey: UserKeys.html_url.rawValue) 208 | objectUpdate.setValue(currentProduct.followers_url, forKey: UserKeys.followers_url.rawValue) 209 | objectUpdate.setValue(currentProduct.following_url, forKey: UserKeys.following_url.rawValue) 210 | objectUpdate.setValue(currentProduct.gists_url, forKey: UserKeys.gists_url.rawValue) 211 | objectUpdate.setValue(currentProduct.starred_url, forKey: UserKeys.starred_url.rawValue) 212 | objectUpdate.setValue(currentProduct.subscriptions_url, forKey: UserKeys.subscriptions_url.rawValue) 213 | objectUpdate.setValue(currentProduct.organizations_url, forKey: UserKeys.organizations_url.rawValue) 214 | objectUpdate.setValue(currentProduct.repos_url, forKey: UserKeys.repos_url.rawValue) 215 | objectUpdate.setValue(currentProduct.events_url, forKey: UserKeys.events_url.rawValue) 216 | objectUpdate.setValue(currentProduct.received_events_url, forKey: UserKeys.received_events_url.rawValue) 217 | objectUpdate.setValue(currentProduct.type, forKey: UserKeys.type.rawValue) 218 | objectUpdate.setValue(currentProduct.site_admin, forKey: UserKeys.site_admin.rawValue) 219 | objectUpdate.setValue(notes, forKey: UserKeys.notes.rawValue) 220 | 221 | do { 222 | self.coreDataStack.saveMainContext() 223 | 224 | UtilityFunctions.printToConsole(message: "updated") 225 | UtilityFunctions.showAlert(message: "Notes updated successfully") 226 | }catch let error as NSError { 227 | print(error.localizedFailureReason ?? "") 228 | } 229 | } 230 | catch let error as NSError { 231 | print(error.localizedFailureReason ?? "") 232 | } 233 | 234 | } 235 | } 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Pods/ReachabilitySwift/Sources/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, Int32) 33 | case failedToCreateWithHostname(String, Int32) 34 | case unableToSetCallback(Int32) 35 | case unableToSetDispatchQueue(Int32) 36 | case unableToGetFlags(Int32) 37 | } 38 | 39 | @available(*, unavailable, renamed: "Notification.Name.reachabilityChanged") 40 | public let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification") 41 | 42 | public extension Notification.Name { 43 | static let reachabilityChanged = Notification.Name("reachabilityChanged") 44 | } 45 | 46 | public class Reachability { 47 | 48 | public typealias NetworkReachable = (Reachability) -> () 49 | public typealias NetworkUnreachable = (Reachability) -> () 50 | 51 | @available(*, unavailable, renamed: "Connection") 52 | public enum NetworkStatus: CustomStringConvertible { 53 | case notReachable, reachableViaWiFi, reachableViaWWAN 54 | public var description: String { 55 | switch self { 56 | case .reachableViaWWAN: return "Cellular" 57 | case .reachableViaWiFi: return "WiFi" 58 | case .notReachable: return "No Connection" 59 | } 60 | } 61 | } 62 | 63 | public enum Connection: CustomStringConvertible { 64 | @available(*, deprecated, renamed: "unavailable") 65 | case none 66 | case unavailable, wifi, cellular 67 | public var description: String { 68 | switch self { 69 | case .cellular: return "Cellular" 70 | case .wifi: return "WiFi" 71 | case .unavailable: return "No Connection" 72 | case .none: return "unavailable" 73 | } 74 | } 75 | } 76 | 77 | public var whenReachable: NetworkReachable? 78 | public var whenUnreachable: NetworkUnreachable? 79 | 80 | @available(*, deprecated, renamed: "allowsCellularConnection") 81 | public let reachableOnWWAN: Bool = true 82 | 83 | /// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`) 84 | public var allowsCellularConnection: Bool 85 | 86 | // The notification center on which "reachability changed" events are being posted 87 | public var notificationCenter: NotificationCenter = NotificationCenter.default 88 | 89 | @available(*, deprecated, renamed: "connection.description") 90 | public var currentReachabilityString: String { 91 | return "\(connection)" 92 | } 93 | 94 | @available(*, unavailable, renamed: "connection") 95 | public var currentReachabilityStatus: Connection { 96 | return connection 97 | } 98 | 99 | public var connection: Connection { 100 | if flags == nil { 101 | try? setReachabilityFlags() 102 | } 103 | 104 | switch flags?.connection { 105 | case .unavailable?, nil: return .unavailable 106 | case .none?: return .unavailable 107 | case .cellular?: return allowsCellularConnection ? .cellular : .unavailable 108 | case .wifi?: return .wifi 109 | } 110 | } 111 | 112 | fileprivate var isRunningOnDevice: Bool = { 113 | #if targetEnvironment(simulator) 114 | return false 115 | #else 116 | return true 117 | #endif 118 | }() 119 | 120 | fileprivate(set) var notifierRunning = false 121 | fileprivate let reachabilityRef: SCNetworkReachability 122 | fileprivate let reachabilitySerialQueue: DispatchQueue 123 | fileprivate let notificationQueue: DispatchQueue? 124 | fileprivate(set) var flags: SCNetworkReachabilityFlags? { 125 | didSet { 126 | guard flags != oldValue else { return } 127 | notifyReachabilityChanged() 128 | } 129 | } 130 | 131 | required public init(reachabilityRef: SCNetworkReachability, 132 | queueQoS: DispatchQoS = .default, 133 | targetQueue: DispatchQueue? = nil, 134 | notificationQueue: DispatchQueue? = .main) { 135 | self.allowsCellularConnection = true 136 | self.reachabilityRef = reachabilityRef 137 | self.reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability", qos: queueQoS, target: targetQueue) 138 | self.notificationQueue = notificationQueue 139 | } 140 | 141 | public convenience init(hostname: String, 142 | queueQoS: DispatchQoS = .default, 143 | targetQueue: DispatchQueue? = nil, 144 | notificationQueue: DispatchQueue? = .main) throws { 145 | guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { 146 | throw ReachabilityError.failedToCreateWithHostname(hostname, SCError()) 147 | } 148 | self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) 149 | } 150 | 151 | public convenience init(queueQoS: DispatchQoS = .default, 152 | targetQueue: DispatchQueue? = nil, 153 | notificationQueue: DispatchQueue? = .main) throws { 154 | var zeroAddress = sockaddr() 155 | zeroAddress.sa_len = UInt8(MemoryLayout.size) 156 | zeroAddress.sa_family = sa_family_t(AF_INET) 157 | 158 | guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { 159 | throw ReachabilityError.failedToCreateWithAddress(zeroAddress, SCError()) 160 | } 161 | 162 | self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) 163 | } 164 | 165 | deinit { 166 | stopNotifier() 167 | } 168 | } 169 | 170 | public extension Reachability { 171 | 172 | // MARK: - *** Notifier methods *** 173 | func startNotifier() throws { 174 | guard !notifierRunning else { return } 175 | 176 | let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in 177 | guard let info = info else { return } 178 | 179 | // `weakifiedReachability` is guaranteed to exist by virtue of our 180 | // retain/release callbacks which we provided to the `SCNetworkReachabilityContext`. 181 | let weakifiedReachability = Unmanaged.fromOpaque(info).takeUnretainedValue() 182 | 183 | // The weak `reachability` _may_ no longer exist if the `Reachability` 184 | // object has since been deallocated but a callback was already in flight. 185 | weakifiedReachability.reachability?.flags = flags 186 | } 187 | 188 | let weakifiedReachability = ReachabilityWeakifier(reachability: self) 189 | let opaqueWeakifiedReachability = Unmanaged.passUnretained(weakifiedReachability).toOpaque() 190 | 191 | var context = SCNetworkReachabilityContext( 192 | version: 0, 193 | info: UnsafeMutableRawPointer(opaqueWeakifiedReachability), 194 | retain: { (info: UnsafeRawPointer) -> UnsafeRawPointer in 195 | let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) 196 | _ = unmanagedWeakifiedReachability.retain() 197 | return UnsafeRawPointer(unmanagedWeakifiedReachability.toOpaque()) 198 | }, 199 | release: { (info: UnsafeRawPointer) -> Void in 200 | let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) 201 | unmanagedWeakifiedReachability.release() 202 | }, 203 | copyDescription: { (info: UnsafeRawPointer) -> Unmanaged in 204 | let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) 205 | let weakifiedReachability = unmanagedWeakifiedReachability.takeUnretainedValue() 206 | let description = weakifiedReachability.reachability?.description ?? "nil" 207 | return Unmanaged.passRetained(description as CFString) 208 | } 209 | ) 210 | 211 | if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) { 212 | stopNotifier() 213 | throw ReachabilityError.unableToSetCallback(SCError()) 214 | } 215 | 216 | if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) { 217 | stopNotifier() 218 | throw ReachabilityError.unableToSetDispatchQueue(SCError()) 219 | } 220 | 221 | // Perform an initial check 222 | try setReachabilityFlags() 223 | 224 | notifierRunning = true 225 | } 226 | 227 | func stopNotifier() { 228 | defer { notifierRunning = false } 229 | 230 | SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil) 231 | SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil) 232 | } 233 | 234 | // MARK: - *** Connection test methods *** 235 | @available(*, deprecated, message: "Please use `connection != .none`") 236 | var isReachable: Bool { 237 | return connection != .unavailable 238 | } 239 | 240 | @available(*, deprecated, message: "Please use `connection == .cellular`") 241 | var isReachableViaWWAN: Bool { 242 | // Check we're not on the simulator, we're REACHABLE and check we're on WWAN 243 | return connection == .cellular 244 | } 245 | 246 | @available(*, deprecated, message: "Please use `connection == .wifi`") 247 | var isReachableViaWiFi: Bool { 248 | return connection == .wifi 249 | } 250 | 251 | var description: String { 252 | return flags?.description ?? "unavailable flags" 253 | } 254 | } 255 | 256 | fileprivate extension Reachability { 257 | 258 | func setReachabilityFlags() throws { 259 | try reachabilitySerialQueue.sync { [unowned self] in 260 | var flags = SCNetworkReachabilityFlags() 261 | if !SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) { 262 | self.stopNotifier() 263 | throw ReachabilityError.unableToGetFlags(SCError()) 264 | } 265 | 266 | self.flags = flags 267 | } 268 | } 269 | 270 | 271 | func notifyReachabilityChanged() { 272 | let notify = { [weak self] in 273 | guard let self = self else { return } 274 | self.connection != .unavailable ? self.whenReachable?(self) : self.whenUnreachable?(self) 275 | self.notificationCenter.post(name: .reachabilityChanged, object: self) 276 | } 277 | 278 | // notify on the configured `notificationQueue`, or the caller's (i.e. `reachabilitySerialQueue`) 279 | notificationQueue?.async(execute: notify) ?? notify() 280 | } 281 | } 282 | 283 | extension SCNetworkReachabilityFlags { 284 | 285 | typealias Connection = Reachability.Connection 286 | 287 | var connection: Connection { 288 | guard isReachableFlagSet else { return .unavailable } 289 | 290 | // If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi 291 | #if targetEnvironment(simulator) 292 | return .wifi 293 | #else 294 | var connection = Connection.unavailable 295 | 296 | if !isConnectionRequiredFlagSet { 297 | connection = .wifi 298 | } 299 | 300 | if isConnectionOnTrafficOrDemandFlagSet { 301 | if !isInterventionRequiredFlagSet { 302 | connection = .wifi 303 | } 304 | } 305 | 306 | if isOnWWANFlagSet { 307 | connection = .cellular 308 | } 309 | 310 | return connection 311 | #endif 312 | } 313 | 314 | var isOnWWANFlagSet: Bool { 315 | #if os(iOS) 316 | return contains(.isWWAN) 317 | #else 318 | return false 319 | #endif 320 | } 321 | var isReachableFlagSet: Bool { 322 | return contains(.reachable) 323 | } 324 | var isConnectionRequiredFlagSet: Bool { 325 | return contains(.connectionRequired) 326 | } 327 | var isInterventionRequiredFlagSet: Bool { 328 | return contains(.interventionRequired) 329 | } 330 | var isConnectionOnTrafficFlagSet: Bool { 331 | return contains(.connectionOnTraffic) 332 | } 333 | var isConnectionOnDemandFlagSet: Bool { 334 | return contains(.connectionOnDemand) 335 | } 336 | var isConnectionOnTrafficOrDemandFlagSet: Bool { 337 | return !intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty 338 | } 339 | var isTransientConnectionFlagSet: Bool { 340 | return contains(.transientConnection) 341 | } 342 | var isLocalAddressFlagSet: Bool { 343 | return contains(.isLocalAddress) 344 | } 345 | var isDirectFlagSet: Bool { 346 | return contains(.isDirect) 347 | } 348 | var isConnectionRequiredAndTransientFlagSet: Bool { 349 | return intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection] 350 | } 351 | 352 | var description: String { 353 | let W = isOnWWANFlagSet ? "W" : "-" 354 | let R = isReachableFlagSet ? "R" : "-" 355 | let c = isConnectionRequiredFlagSet ? "c" : "-" 356 | let t = isTransientConnectionFlagSet ? "t" : "-" 357 | let i = isInterventionRequiredFlagSet ? "i" : "-" 358 | let C = isConnectionOnTrafficFlagSet ? "C" : "-" 359 | let D = isConnectionOnDemandFlagSet ? "D" : "-" 360 | let l = isLocalAddressFlagSet ? "l" : "-" 361 | let d = isDirectFlagSet ? "d" : "-" 362 | 363 | return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)" 364 | } 365 | } 366 | 367 | /** 368 | `ReachabilityWeakifier` weakly wraps the `Reachability` class 369 | in order to break retain cycles when interacting with CoreFoundation. 370 | 371 | CoreFoundation callbacks expect a pair of retain/release whenever an 372 | opaque `info` parameter is provided. These callbacks exist to guard 373 | against memory management race conditions when invoking the callbacks. 374 | 375 | #### Race Condition 376 | 377 | If we passed `SCNetworkReachabilitySetCallback` a direct reference to our 378 | `Reachability` class without also providing corresponding retain/release 379 | callbacks, then a race condition can lead to crashes when: 380 | - `Reachability` is deallocated on thread X 381 | - A `SCNetworkReachability` callback(s) is already in flight on thread Y 382 | 383 | #### Retain Cycle 384 | 385 | If we pass `Reachability` to CoreFoundtion while also providing retain/ 386 | release callbacks, we would create a retain cycle once CoreFoundation 387 | retains our `Reachability` class. This fixes the crashes and his how 388 | CoreFoundation expects the API to be used, but doesn't play nicely with 389 | Swift/ARC. This cycle would only be broken after manually calling 390 | `stopNotifier()` — `deinit` would never be called. 391 | 392 | #### ReachabilityWeakifier 393 | 394 | By providing both retain/release callbacks and wrapping `Reachability` in 395 | a weak wrapper, we: 396 | - interact correctly with CoreFoundation, thereby avoiding a crash. 397 | See "Memory Management Programming Guide for Core Foundation". 398 | - don't alter the public API of `Reachability.swift` in any way 399 | - still allow for automatic stopping of the notifier on `deinit`. 400 | */ 401 | private class ReachabilityWeakifier { 402 | weak var reachability: Reachability? 403 | init(reachability: Reachability) { 404 | self.reachability = reachability 405 | } 406 | } 407 | --------------------------------------------------------------------------------