├── MVVM with RxSwift ├── Assets │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── MVVM_with_RxSwift.xcdatamodeld │ │ ├── .xccurrentversion │ │ └── MVVM_with_RxSwift.xcdatamodel │ │ └── contents ├── Module │ ├── UseCase │ │ ├── UsersUseCaseProtocol.swift │ │ └── UsersUseCase.swift │ ├── Model │ │ ├── UsersSectionModel.swift │ │ └── UsersModel.swift │ ├── ViewModel │ │ └── UsersViewModel.swift │ └── ViewController │ │ └── UsersViewController.swift ├── States │ └── States.swift ├── Extentions │ ├── Alerts+Ext.swift │ └── LoadingIndicator+Ext.swift ├── Info.plist ├── Storyboard │ └── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard └── AppDelegate │ ├── SceneDelegate.swift │ └── AppDelegate.swift ├── MVVM with RxSwift.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── alifayed.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── project.pbxproj ├── MVVM with RxSwiftTests ├── UsersModuleTests │ ├── Stubs and Mocks │ │ ├── JSONMocking.swift │ │ └── UsersUseCaseMock.swift │ ├── UsersViewModelTests.swift │ └── UsersUseCaseTests.swift └── StubRequests.swift ├── Podfile ├── MVVM with RxSwiftUITests ├── MVVM_with_RxSwiftUITestsLaunchTests.swift └── MVVM_with_RxSwiftUITests.swift └── README.md /MVVM with RxSwift/Assets/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /MVVM with RxSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Assets/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 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/UseCase/UsersUseCaseProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersUseCaseProtocol.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | 11 | protocol UsersUseCaseProtocol { 12 | func fetchUsers() -> AnyPublisher<[Users], Error>? 13 | } 14 | -------------------------------------------------------------------------------- /MVVM with RxSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Assets/MVVM_with_RxSwift.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | MVVM_with_RxSwift.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /MVVM with RxSwift/States/States.swift: -------------------------------------------------------------------------------- 1 | // 2 | // States.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | import RxCocoa 10 | import RxSwift 11 | 12 | class States { 13 | var loadingState = BehaviorRelay(value: false) 14 | var errorState = BehaviorRelay<(Bool, String)>(value: (false, "")) 15 | } 16 | -------------------------------------------------------------------------------- /MVVM with RxSwiftTests/UsersModuleTests/Stubs and Mocks/JSONMocking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // fakeJSON.swift 3 | // MVVM with RxSwiftTests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | 10 | class JSONMocking { 11 | static let shared = JSONMocking() 12 | private init() {} 13 | let fakeJSON: [String: Any] = [ 14 | "login" : "mojombo" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Assets/MVVM_with_RxSwift.xcdatamodeld/MVVM_with_RxSwift.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/Model/UsersSectionModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersSectionModel.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import RxDataSources 9 | 10 | struct UsersSectionModel { 11 | var header: String 12 | var items: [Users] 13 | } 14 | extension UsersSectionModel: SectionModelType { 15 | init(original: UsersSectionModel, items: [Users]) { 16 | self = original 17 | self.items = items 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MVVM with RxSwift.xcodeproj/xcuserdata/alifayed.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MVVM with RxSwift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 10 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MVVM with RxSwiftTests/UsersModuleTests/Stubs and Mocks/UsersUseCaseMock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersUseCaseMock.swift 3 | // MVVM with RxSwiftTests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | @testable import MVVM_with_RxSwift 11 | class UsersUseCaseMock: UsersUseCaseProtocol { 12 | var fetchUsersComplete = false 13 | func fetchUsers() -> AnyPublisher<[Users], Error>? { 14 | fetchUsersComplete = true 15 | return nil 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/Model/UsersModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersModel.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | 10 | struct Users { 11 | let userName: String? 12 | 13 | enum PostCodingKeys: String, CodingKey { 14 | case userName = "login" 15 | } 16 | } 17 | //MARK: - Decodable init 18 | extension Users: Decodable { 19 | init(from decoder: Decoder) throws { 20 | let container = try decoder.container(keyedBy: PostCodingKeys.self) 21 | userName = try container.decode(String.self, forKey: .userName) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'MVVM with RxSwift' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for MVVM with RxSwift 9 | pod 'RxSwift', '6.2.0' 10 | pod 'RxCocoa', '6.2.0' 11 | pod 'RxDataSources', '~> 5.0' 12 | pod 'MBProgressHUD', '~> 1.2.0' 13 | pod 'OHHTTPStubs/Swift' 14 | 15 | target 'MVVM with RxSwiftTests' do 16 | inherit! :search_paths 17 | # Pods for testing 18 | end 19 | 20 | target 'MVVM with RxSwiftUITests' do 21 | # Pods for testing 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Extentions/Alerts+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts+Ext.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIViewController { 11 | typealias ActionCompletion = ((UIAlertAction) -> Void)? 12 | func alertWithOneAction(title: String, msg: String, btnTitle: String, completion: ActionCompletion = nil) { 13 | let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert) 14 | let action = UIAlertAction(title: btnTitle, style: .default, handler: completion) 15 | alert.addAction(action) 16 | self.present(alert, animated: true) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MVVM with RxSwiftTests/StubRequests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StubRequests.swift 3 | // MVVM with RxSwiftTests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import OHHTTPStubs 9 | 10 | class StubRequests { 11 | static let shared = StubRequests() 12 | private init() {} 13 | func stubJSONrespone (jsonObject: [[String: Any]], header: [String: String]?, statusCode: Int32, absoluteStringWord: String) { 14 | stub(condition: { (urlRequest) -> Bool in 15 | return urlRequest.url?.absoluteString.contains(absoluteStringWord) ?? false 16 | }) { (_) -> HTTPStubsResponse in 17 | return HTTPStubsResponse(jsonObject: jsonObject, statusCode: statusCode, headers: header) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Extentions/LoadingIndicator+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoadingIndicator+Ext.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import UIKit 9 | import MBProgressHUD 10 | 11 | extension UIViewController { 12 | func showIndicator(withTitle title: String, and Description:String) { 13 | let Indicator = MBProgressHUD.showAdded(to: self.view, animated: true) 14 | Indicator.label.text = title 15 | Indicator.isUserInteractionEnabled = false 16 | Indicator.detailsLabel.text = Description 17 | Indicator.show(animated: true) 18 | self.view.isUserInteractionEnabled = false 19 | } 20 | func hideIndicator() { 21 | MBProgressHUD.hide(for: self.view, animated: true) 22 | self.view.isUserInteractionEnabled = true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MVVM with RxSwift/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 | -------------------------------------------------------------------------------- /MVVM with RxSwiftTests/UsersModuleTests/UsersViewModelTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersViewModelTests.swift 3 | // MVVM with RxSwiftTests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import XCTest 9 | @testable import MVVM_with_RxSwift 10 | class UsersViewModelTests: XCTestCase { 11 | var sut: UsersViewModel! 12 | var usersUseCaseMock = UsersUseCaseMock() 13 | override func setUp() { 14 | sut = UsersViewModel(useCase: usersUseCaseMock) 15 | super.setUp() 16 | } 17 | override func tearDown() { 18 | sut = nil 19 | super.tearDown() 20 | } 21 | func testRequstData() throws { 22 | // when 23 | sut.fetchUsers() 24 | // then 25 | XCTAssertTrue(usersUseCaseMock.fetchUsersComplete, "Users fetch request called successfully") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MVVM with RxSwiftUITests/MVVM_with_RxSwiftUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MVVM_with_RxSwiftUITestsLaunchTests.swift 3 | // MVVM with RxSwiftUITests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import XCTest 9 | 10 | class MVVM_with_RxSwiftUITestsLaunchTests: 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 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/UseCase/UsersUseCase.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersUseCase.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | 11 | class UsersUseCase: UsersUseCaseProtocol { 12 | static let shared = UsersUseCase() 13 | private init () {} 14 | func fetchUsers() -> AnyPublisher<[Users], Error>? { 15 | let url = URL(string: "https://api.github.com/users") 16 | return URLSession.shared.dataTaskPublisher(for: url!) 17 | .map({$0.data}) 18 | .decode(type: [Users].self, decoder: JSONDecoder()) 19 | .mapError({ error in 20 | switch error { 21 | case is Swift.DecodingError: 22 | return error 23 | default: 24 | return error 25 | } 26 | }) 27 | .subscribe(on: DispatchQueue.global()) 28 | .receive(on: DispatchQueue.main) 29 | .eraseToAnyPublisher() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MVVM with RxSwiftTests/UsersModuleTests/UsersUseCaseTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersUseCaseTests.swift 3 | // MVVM with RxSwiftTests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import XCTest 9 | import Combine 10 | @testable import MVVM_with_RxSwift 11 | 12 | class UsersUseCaseTests: XCTestCase { 13 | // sut = system under test 14 | var sut: UsersUseCase! 15 | let stubRequest = StubRequests.shared 16 | let jsonMock = JSONMocking.shared 17 | var observer: AnyCancellable? 18 | override func setUp() { 19 | super.setUp() 20 | sut = UsersUseCase.shared 21 | } 22 | override func tearDown() { 23 | sut = nil 24 | super.tearDown() 25 | } 26 | func testFetchNewsList() { 27 | let exception = self.expectation(description: "Fetch Users Failed") 28 | var expectedResults: [Users] = [] 29 | stubRequest.stubJSONrespone(jsonObject: [jsonMock.fakeJSON], header: nil, statusCode: 200, absoluteStringWord: "/users") 30 | observer = sut.fetchUsers()? 31 | .sink(receiveCompletion: { completion in 32 | switch completion { 33 | case .finished: 34 | break 35 | case .failure(let error): 36 | XCTAssertNotNil(error.localizedDescription) 37 | } 38 | }, receiveValue: { model in 39 | expectedResults = model 40 | exception.fulfill() 41 | }) 42 | XCTAssertNotNil(expectedResults) 43 | self.waitForExpectations(timeout: 1, handler: nil) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MVVM with RxSwiftUITests/MVVM_with_RxSwiftUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MVVM_with_RxSwiftUITests.swift 3 | // MVVM with RxSwiftUITests 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import XCTest 9 | 10 | class MVVM_with_RxSwiftUITests: 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 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Storyboard/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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Hi there, This is MVVM example app with RxSwift & RxDataSources & Dependency Injection & UnitTests and more 👋 2 | 3 | 4 | SwiftIOSApp Store 5 | 6 | 7 | ## MVVM with RxSwift Example Features: 8 | 9 | - Real World BasicApp with MVVM and binding using RxSwift you can scale it easly. 10 | - API Calls with Combine DataTaskPublisher 11 | - Handle Error with Combine ErrorMaping. 12 | - Passing data with Combine AnyPuplisher. 13 | - Handle All App States with RxSwift Observables like loading and error. 14 | - Initializte Dependencies to ViewModel with Dependency Injection. 15 | - Advanced Sectioned TableView with RxDataSources. 16 | - Unit Tests for Usecase and ViewModel with Mocking and Stubs. 17 | 18 | ## Important Notes: 19 | 20 | - open your terminal type 'cd' and drag the project folder and type this line: 21 | ``` 22 | pod install 23 | ``` 24 | [contact]: https://www.linkedin.com/in/ali-fayed-8682aa1a6/ 25 | [fb]: https://www.facebook.com/alifayed26/ 26 | [tw]: https://www.twitter.com/Aliifayed 27 | [mail]: https://docs.google.com/document/d/1Oo4S9pl0yM4K4uewlOh7poLAmEKLbjnFelIYHxBQL7o/edit?usp=sharing 28 | 29 | 30 | ## Contact Me: 31 | 32 | [LinkedIn][contact] [Facebook][fb] [Twitter][tw] [Gmail][mail] 33 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Assets/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 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/ViewModel/UsersViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewModel.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | import RxSwift 11 | import RxCocoa 12 | import RxDataSources 13 | 14 | class UsersViewModel { 15 | var observer: AnyCancellable? 16 | let useCase: UsersUseCaseProtocol 17 | let states = States() 18 | private var usersSectionModel = [UsersSectionModel]() 19 | private let usersListSubjet = PublishSubject<[UsersSectionModel]>() 20 | var usersListObservable: Observable<[UsersSectionModel]> { 21 | return usersListSubjet 22 | } 23 | //MARK: - Initialization 24 | init(useCase: UsersUseCaseProtocol = UsersUseCase.shared) { 25 | self.useCase = useCase 26 | } 27 | //MARK: - Methods 28 | func fetchUsers() { 29 | states.loadingState.accept(true) 30 | observer = useCase.fetchUsers()? 31 | .sink(receiveCompletion: { [weak self] completion in 32 | guard let self = self else {return} 33 | switch completion { 34 | case .finished: 35 | self.states.loadingState.accept(false) 36 | case .failure(let error): 37 | self.states.errorState.accept((true, error.localizedDescription)) 38 | } 39 | }, receiveValue: { [weak self] users in 40 | guard let self = self else {return} 41 | self.usersSectionModel.append(UsersSectionModel(header: "TopUsers", items: users.dropLast(25))) 42 | self.usersSectionModel.append(UsersSectionModel(header: "MiddleUsers", items: users.dropLast(28).reversed())) 43 | self.usersSectionModel.append(UsersSectionModel(header: "LastUsers", items: users.dropLast(26).reversed())) 44 | self.usersListSubjet.onNext(self.usersSectionModel) 45 | self.usersListSubjet.onCompleted() 46 | }) 47 | } 48 | func tableViewDataSource() -> RxTableViewSectionedReloadDataSource { 49 | let dataSource = RxTableViewSectionedReloadDataSource( 50 | configureCell: { (_, tableView, indexPath, items) in 51 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 52 | cell.textLabel?.text = items.userName 53 | return cell 54 | }, 55 | titleForHeaderInSection: { dataSource, sectionIndex in 56 | return dataSource[sectionIndex].header 57 | } 58 | ) 59 | return dataSource 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Module/ViewController/UsersViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UsersViewController.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import UIKit 9 | import RxSwift 10 | import RxCocoa 11 | 12 | class UsersViewController: UIViewController { 13 | //MARK: - Props 14 | @IBOutlet weak var tableView: UITableView! 15 | private let refreshControl = UIRefreshControl() 16 | private var viewModel = UsersViewModel() 17 | private let bag = DisposeBag() 18 | //MARK: - LifeCycle 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | viewModel.fetchUsers() 22 | bindDataToTableView() 23 | tableViewRefreshControl() 24 | subscribeToTableViewCellSelection() 25 | subscribeToErrorBehaviour() 26 | subsribeToLoadingBehaviour() 27 | } 28 | //MARK: - TableView 29 | func bindDataToTableView() { 30 | viewModel.usersListObservable.bind(to: tableView.rx.items(dataSource: viewModel.tableViewDataSource())) 31 | .disposed(by: bag) 32 | } 33 | func subscribeToTableViewCellSelection() { 34 | Observable 35 | .zip(tableView.rx.itemSelected, tableView.rx.modelSelected(Users.self)) 36 | .bind { [weak self] indexPath, users in 37 | guard let self = self else { return } 38 | self.tableView.deselectRow(at: indexPath, animated: true) 39 | print(users) 40 | }.disposed(by: bag) 41 | } 42 | func tableViewRefreshControl() { 43 | refreshControl.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged) 44 | tableView.addSubview(refreshControl) 45 | } 46 | @objc func didPullToRefresh() { 47 | self.viewModel.fetchUsers() 48 | self.refreshControl.endRefreshing() 49 | } 50 | //MARK: - Loading 51 | func subsribeToLoadingBehaviour() { 52 | viewModel.states.loadingState.subscribe(onNext: { [weak self] (isLoading) in 53 | guard let self = self else { return } 54 | isLoading ? self.showIndicator(withTitle: "Loading", and: "") : self.hideIndicator() 55 | }).disposed(by: bag) 56 | } 57 | //MARK: - Error 58 | func subscribeToErrorBehaviour() { 59 | viewModel.states.errorState.subscribe(onNext: { [weak self] (error) in 60 | guard let self = self else { return } 61 | let ifResponseFailed = error.0 62 | let errorMessage = error.1 63 | if ifResponseFailed { 64 | self.alertWithOneAction(title: "Error", msg: errorMessage, btnTitle: "Ok") 65 | } 66 | }).disposed(by: bag) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /MVVM with RxSwift/AppDelegate/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 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 | func sceneDidDisconnect(_ scene: UIScene) { 23 | // Called as the scene is being released by the system. 24 | // This occurs shortly after the scene enters the background, or when its session is discarded. 25 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 26 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 27 | } 28 | 29 | func sceneDidBecomeActive(_ scene: UIScene) { 30 | // Called when the scene has moved from an inactive state to an active state. 31 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 32 | } 33 | 34 | func sceneWillResignActive(_ scene: UIScene) { 35 | // Called when the scene will move from an active state to an inactive state. 36 | // This may occur due to temporary interruptions (ex. an incoming phone call). 37 | } 38 | 39 | func sceneWillEnterForeground(_ scene: UIScene) { 40 | // Called as the scene transitions from the background to the foreground. 41 | // Use this method to undo the changes made on entering the background. 42 | } 43 | 44 | func sceneDidEnterBackground(_ scene: UIScene) { 45 | // Called as the scene transitions from the foreground to the background. 46 | // Use this method to save data, release shared resources, and store enough scene-specific state information 47 | // to restore the scene back to its current state. 48 | 49 | // Save changes in the application's managed object context when the application transitions to the background. 50 | (UIApplication.shared.delegate as? AppDelegate)?.saveContext() 51 | } 52 | 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /MVVM with RxSwift/AppDelegate/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MVVM with RxSwift 4 | // 5 | // Created by Ali Fayed on 28/11/2021. 6 | // 7 | 8 | import UIKit 9 | import CoreData 10 | import MBProgressHUD 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 | return true 20 | } 21 | 22 | // MARK: UISceneSession Lifecycle 23 | 24 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 25 | // Called when a new scene session is being created. 26 | // Use this method to select a configuration to create the new scene with. 27 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 28 | } 29 | 30 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 31 | // Called when the user discards a scene session. 32 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 33 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 34 | } 35 | 36 | // MARK: - Core Data stack 37 | 38 | lazy var persistentContainer: NSPersistentContainer = { 39 | /* 40 | The persistent container for the application. This implementation 41 | creates and returns a container, having loaded the store for the 42 | application to it. This property is optional since there are legitimate 43 | error conditions that could cause the creation of the store to fail. 44 | */ 45 | let container = NSPersistentContainer(name: "MVVM_with_RxSwift") 46 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 47 | if let error = error as NSError? { 48 | // Replace this implementation with code to handle the error appropriately. 49 | // 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. 50 | 51 | /* 52 | Typical reasons for an error here include: 53 | * The parent directory does not exist, cannot be created, or disallows writing. 54 | * The persistent store is not accessible, due to permissions or data protection when the device is locked. 55 | * The device is out of space. 56 | * The store could not be migrated to the current model version. 57 | Check the error message to determine what the actual problem was. 58 | */ 59 | fatalError("Unresolved error \(error), \(error.userInfo)") 60 | } 61 | }) 62 | return container 63 | }() 64 | 65 | // MARK: - Core Data Saving support 66 | 67 | func saveContext () { 68 | let context = persistentContainer.viewContext 69 | if context.hasChanges { 70 | do { 71 | try context.save() 72 | } catch { 73 | // Replace this implementation with code to handle the error appropriately. 74 | // 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. 75 | let nserror = error as NSError 76 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 77 | } 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /MVVM with RxSwift/Storyboard/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /MVVM with RxSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7E07C56160C14C25B8616872 /* Pods_MVVM_with_RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E42D610E1C65242A3294F95F /* Pods_MVVM_with_RxSwift.framework */; }; 11 | B44374FE792A8842BF71DF79 /* Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1749B08B3568EB040275B022 /* Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework */; }; 12 | DFF43A88339F48942BEC547E /* Pods_MVVM_with_RxSwiftTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C73F5284F547AC64A0CAD650 /* Pods_MVVM_with_RxSwiftTests.framework */; }; 13 | EAD5C00B275397EE00CC2766 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C00A275397EE00CC2766 /* AppDelegate.swift */; }; 14 | EAD5C00D275397EE00CC2766 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C00C275397EE00CC2766 /* SceneDelegate.swift */; }; 15 | EAD5C00F275397EE00CC2766 /* UsersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C00E275397EE00CC2766 /* UsersViewController.swift */; }; 16 | EAD5C012275397EE00CC2766 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAD5C010275397EE00CC2766 /* Main.storyboard */; }; 17 | EAD5C015275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C013275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodeld */; }; 18 | EAD5C017275397F100CC2766 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAD5C016275397F100CC2766 /* Assets.xcassets */; }; 19 | EAD5C01A275397F100CC2766 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAD5C018275397F100CC2766 /* LaunchScreen.storyboard */; }; 20 | EAD5C02F275397F200CC2766 /* MVVM_with_RxSwiftUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C02E275397F200CC2766 /* MVVM_with_RxSwiftUITests.swift */; }; 21 | EAD5C031275397F200CC2766 /* MVVM_with_RxSwiftUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C030275397F200CC2766 /* MVVM_with_RxSwiftUITestsLaunchTests.swift */; }; 22 | EAD5C0422753983900CC2766 /* UsersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0412753983900CC2766 /* UsersModel.swift */; }; 23 | EAD5C0442753984400CC2766 /* UsersUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0432753984400CC2766 /* UsersUseCase.swift */; }; 24 | EAD5C0462753985B00CC2766 /* UsersUseCaseProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0452753985B00CC2766 /* UsersUseCaseProtocol.swift */; }; 25 | EAD5C0482753990300CC2766 /* UsersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0472753990300CC2766 /* UsersViewModel.swift */; }; 26 | EAD5C04D2753AD9D00CC2766 /* Alerts+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C04C2753AD9D00CC2766 /* Alerts+Ext.swift */; }; 27 | EAD5C04F2753ADAB00CC2766 /* LoadingIndicator+Ext.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C04E2753ADAB00CC2766 /* LoadingIndicator+Ext.swift */; }; 28 | EAD5C0572753C5BA00CC2766 /* UsersSectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0562753C5BA00CC2766 /* UsersSectionModel.swift */; }; 29 | EAD5C05A2753CE9D00CC2766 /* JSONMocking.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0592753CE9D00CC2766 /* JSONMocking.swift */; }; 30 | EAD5C05C2753CEAB00CC2766 /* UsersUseCaseMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C05B2753CEAB00CC2766 /* UsersUseCaseMock.swift */; }; 31 | EAD5C05E2753CEC100CC2766 /* UsersUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C05D2753CEC100CC2766 /* UsersUseCaseTests.swift */; }; 32 | EAD5C0602753CECF00CC2766 /* UsersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C05F2753CECE00CC2766 /* UsersViewModelTests.swift */; }; 33 | EAD5C0622753CEE600CC2766 /* StubRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0612753CEE600CC2766 /* StubRequests.swift */; }; 34 | EAD5C0642753E48400CC2766 /* States.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD5C0632753E48400CC2766 /* States.swift */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | EAD5C021275397F100CC2766 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = EAD5BFFF275397EE00CC2766 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = EAD5C006275397EE00CC2766; 43 | remoteInfo = "MVVM with RxSwift"; 44 | }; 45 | EAD5C02B275397F200CC2766 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = EAD5BFFF275397EE00CC2766 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = EAD5C006275397EE00CC2766; 50 | remoteInfo = "MVVM with RxSwift"; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 0388C88983F05A45E555A5BD /* Pods-MVVM with RxSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwift.debug.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwift/Pods-MVVM with RxSwift.debug.xcconfig"; sourceTree = ""; }; 56 | 1749B08B3568EB040275B022 /* Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 45041708CCBF800C159CB7C3 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.debug.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.debug.xcconfig"; sourceTree = ""; }; 58 | 82C2250A6F207AD6E4F7E033 /* Pods-MVVM with RxSwiftTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwiftTests.release.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwiftTests/Pods-MVVM with RxSwiftTests.release.xcconfig"; sourceTree = ""; }; 59 | A5BE4870BBC3A803270463C8 /* Pods-MVVM with RxSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwift.release.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwift/Pods-MVVM with RxSwift.release.xcconfig"; sourceTree = ""; }; 60 | ADF09A289472C810D4DFD134 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.release.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.release.xcconfig"; sourceTree = ""; }; 61 | C137A675521ACEBAA19DAF49 /* Pods-MVVM with RxSwiftTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MVVM with RxSwiftTests.debug.xcconfig"; path = "Target Support Files/Pods-MVVM with RxSwiftTests/Pods-MVVM with RxSwiftTests.debug.xcconfig"; sourceTree = ""; }; 62 | C73F5284F547AC64A0CAD650 /* Pods_MVVM_with_RxSwiftTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MVVM_with_RxSwiftTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | E42D610E1C65242A3294F95F /* Pods_MVVM_with_RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MVVM_with_RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | EAD5C007275397EE00CC2766 /* MVVM with RxSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MVVM with RxSwift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | EAD5C00A275397EE00CC2766 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 66 | EAD5C00C275397EE00CC2766 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 67 | EAD5C00E275397EE00CC2766 /* UsersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersViewController.swift; sourceTree = ""; }; 68 | EAD5C011275397EE00CC2766 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 69 | EAD5C014275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MVVM_with_RxSwift.xcdatamodel; sourceTree = ""; }; 70 | EAD5C016275397F100CC2766 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | EAD5C019275397F100CC2766 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 72 | EAD5C01B275397F100CC2766 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | EAD5C020275397F100CC2766 /* MVVM with RxSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MVVM with RxSwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | EAD5C02A275397F100CC2766 /* MVVM with RxSwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MVVM with RxSwiftUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | EAD5C02E275397F200CC2766 /* MVVM_with_RxSwiftUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVVM_with_RxSwiftUITests.swift; sourceTree = ""; }; 76 | EAD5C030275397F200CC2766 /* MVVM_with_RxSwiftUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVVM_with_RxSwiftUITestsLaunchTests.swift; sourceTree = ""; }; 77 | EAD5C0412753983900CC2766 /* UsersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersModel.swift; sourceTree = ""; }; 78 | EAD5C0432753984400CC2766 /* UsersUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersUseCase.swift; sourceTree = ""; }; 79 | EAD5C0452753985B00CC2766 /* UsersUseCaseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersUseCaseProtocol.swift; sourceTree = ""; }; 80 | EAD5C0472753990300CC2766 /* UsersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersViewModel.swift; sourceTree = ""; }; 81 | EAD5C04C2753AD9D00CC2766 /* Alerts+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Alerts+Ext.swift"; sourceTree = ""; }; 82 | EAD5C04E2753ADAB00CC2766 /* LoadingIndicator+Ext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LoadingIndicator+Ext.swift"; sourceTree = ""; }; 83 | EAD5C0562753C5BA00CC2766 /* UsersSectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersSectionModel.swift; sourceTree = ""; }; 84 | EAD5C0592753CE9D00CC2766 /* JSONMocking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONMocking.swift; sourceTree = ""; }; 85 | EAD5C05B2753CEAB00CC2766 /* UsersUseCaseMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersUseCaseMock.swift; sourceTree = ""; }; 86 | EAD5C05D2753CEC100CC2766 /* UsersUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersUseCaseTests.swift; sourceTree = ""; }; 87 | EAD5C05F2753CECE00CC2766 /* UsersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UsersViewModelTests.swift; sourceTree = ""; }; 88 | EAD5C0612753CEE600CC2766 /* StubRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StubRequests.swift; sourceTree = ""; }; 89 | EAD5C0632753E48400CC2766 /* States.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = States.swift; sourceTree = ""; }; 90 | /* End PBXFileReference section */ 91 | 92 | /* Begin PBXFrameworksBuildPhase section */ 93 | EAD5C004275397EE00CC2766 /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | 7E07C56160C14C25B8616872 /* Pods_MVVM_with_RxSwift.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | EAD5C01D275397F100CC2766 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | DFF43A88339F48942BEC547E /* Pods_MVVM_with_RxSwiftTests.framework in Frameworks */, 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | EAD5C027275397F100CC2766 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | B44374FE792A8842BF71DF79 /* Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework in Frameworks */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | /* End PBXFrameworksBuildPhase section */ 118 | 119 | /* Begin PBXGroup section */ 120 | 0A9EED412A510937DEDB32FA /* Pods */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 0388C88983F05A45E555A5BD /* Pods-MVVM with RxSwift.debug.xcconfig */, 124 | A5BE4870BBC3A803270463C8 /* Pods-MVVM with RxSwift.release.xcconfig */, 125 | 45041708CCBF800C159CB7C3 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.debug.xcconfig */, 126 | ADF09A289472C810D4DFD134 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.release.xcconfig */, 127 | C137A675521ACEBAA19DAF49 /* Pods-MVVM with RxSwiftTests.debug.xcconfig */, 128 | 82C2250A6F207AD6E4F7E033 /* Pods-MVVM with RxSwiftTests.release.xcconfig */, 129 | ); 130 | path = Pods; 131 | sourceTree = ""; 132 | }; 133 | DDD89F83DF64741DEDE4578F /* Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | E42D610E1C65242A3294F95F /* Pods_MVVM_with_RxSwift.framework */, 137 | 1749B08B3568EB040275B022 /* Pods_MVVM_with_RxSwift_MVVM_with_RxSwiftUITests.framework */, 138 | C73F5284F547AC64A0CAD650 /* Pods_MVVM_with_RxSwiftTests.framework */, 139 | ); 140 | name = Frameworks; 141 | sourceTree = ""; 142 | }; 143 | EAD5BFFE275397EE00CC2766 = { 144 | isa = PBXGroup; 145 | children = ( 146 | EAD5C009275397EE00CC2766 /* MVVM with RxSwift */, 147 | EAD5C023275397F100CC2766 /* MVVM with RxSwiftTests */, 148 | EAD5C02D275397F200CC2766 /* MVVM with RxSwiftUITests */, 149 | EAD5C008275397EE00CC2766 /* Products */, 150 | 0A9EED412A510937DEDB32FA /* Pods */, 151 | DDD89F83DF64741DEDE4578F /* Frameworks */, 152 | ); 153 | sourceTree = ""; 154 | }; 155 | EAD5C008275397EE00CC2766 /* Products */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | EAD5C007275397EE00CC2766 /* MVVM with RxSwift.app */, 159 | EAD5C020275397F100CC2766 /* MVVM with RxSwiftTests.xctest */, 160 | EAD5C02A275397F100CC2766 /* MVVM with RxSwiftUITests.xctest */, 161 | ); 162 | name = Products; 163 | sourceTree = ""; 164 | }; 165 | EAD5C009275397EE00CC2766 /* MVVM with RxSwift */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | EAD5C03D2753980600CC2766 /* AppDelegate */, 169 | EAD5C0402753982300CC2766 /* Module */, 170 | EAD5C0652753EDD000CC2766 /* States */, 171 | EAD5C03E2753981100CC2766 /* Storyboard */, 172 | EAD5C03F2753981D00CC2766 /* Assets */, 173 | EAD5C04B2753AD8A00CC2766 /* Extentions */, 174 | EAD5C01B275397F100CC2766 /* Info.plist */, 175 | ); 176 | path = "MVVM with RxSwift"; 177 | sourceTree = ""; 178 | }; 179 | EAD5C023275397F100CC2766 /* MVVM with RxSwiftTests */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | EAD5C0612753CEE600CC2766 /* StubRequests.swift */, 183 | EAD5C0662753F23500CC2766 /* UsersModuleTests */, 184 | ); 185 | path = "MVVM with RxSwiftTests"; 186 | sourceTree = ""; 187 | }; 188 | EAD5C02D275397F200CC2766 /* MVVM with RxSwiftUITests */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | EAD5C02E275397F200CC2766 /* MVVM_with_RxSwiftUITests.swift */, 192 | EAD5C030275397F200CC2766 /* MVVM_with_RxSwiftUITestsLaunchTests.swift */, 193 | ); 194 | path = "MVVM with RxSwiftUITests"; 195 | sourceTree = ""; 196 | }; 197 | EAD5C03D2753980600CC2766 /* AppDelegate */ = { 198 | isa = PBXGroup; 199 | children = ( 200 | EAD5C00A275397EE00CC2766 /* AppDelegate.swift */, 201 | EAD5C00C275397EE00CC2766 /* SceneDelegate.swift */, 202 | ); 203 | path = AppDelegate; 204 | sourceTree = ""; 205 | }; 206 | EAD5C03E2753981100CC2766 /* Storyboard */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | EAD5C010275397EE00CC2766 /* Main.storyboard */, 210 | EAD5C018275397F100CC2766 /* LaunchScreen.storyboard */, 211 | ); 212 | path = Storyboard; 213 | sourceTree = ""; 214 | }; 215 | EAD5C03F2753981D00CC2766 /* Assets */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | EAD5C016275397F100CC2766 /* Assets.xcassets */, 219 | EAD5C013275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodeld */, 220 | ); 221 | path = Assets; 222 | sourceTree = ""; 223 | }; 224 | EAD5C0402753982300CC2766 /* Module */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | EAD5C0502753AE3100CC2766 /* Model */, 228 | EAD5C0512753AE3700CC2766 /* ViewController */, 229 | EAD5C0522753AE4700CC2766 /* ViewModel */, 230 | EAD5C0532753AE5000CC2766 /* UseCase */, 231 | ); 232 | path = Module; 233 | sourceTree = ""; 234 | }; 235 | EAD5C04B2753AD8A00CC2766 /* Extentions */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | EAD5C04C2753AD9D00CC2766 /* Alerts+Ext.swift */, 239 | EAD5C04E2753ADAB00CC2766 /* LoadingIndicator+Ext.swift */, 240 | ); 241 | path = Extentions; 242 | sourceTree = ""; 243 | }; 244 | EAD5C0502753AE3100CC2766 /* Model */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | EAD5C0412753983900CC2766 /* UsersModel.swift */, 248 | EAD5C0562753C5BA00CC2766 /* UsersSectionModel.swift */, 249 | ); 250 | path = Model; 251 | sourceTree = ""; 252 | }; 253 | EAD5C0512753AE3700CC2766 /* ViewController */ = { 254 | isa = PBXGroup; 255 | children = ( 256 | EAD5C00E275397EE00CC2766 /* UsersViewController.swift */, 257 | ); 258 | path = ViewController; 259 | sourceTree = ""; 260 | }; 261 | EAD5C0522753AE4700CC2766 /* ViewModel */ = { 262 | isa = PBXGroup; 263 | children = ( 264 | EAD5C0472753990300CC2766 /* UsersViewModel.swift */, 265 | ); 266 | path = ViewModel; 267 | sourceTree = ""; 268 | }; 269 | EAD5C0532753AE5000CC2766 /* UseCase */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | EAD5C0432753984400CC2766 /* UsersUseCase.swift */, 273 | EAD5C0452753985B00CC2766 /* UsersUseCaseProtocol.swift */, 274 | ); 275 | path = UseCase; 276 | sourceTree = ""; 277 | }; 278 | EAD5C0582753CE8F00CC2766 /* Stubs and Mocks */ = { 279 | isa = PBXGroup; 280 | children = ( 281 | EAD5C0592753CE9D00CC2766 /* JSONMocking.swift */, 282 | EAD5C05B2753CEAB00CC2766 /* UsersUseCaseMock.swift */, 283 | ); 284 | path = "Stubs and Mocks"; 285 | sourceTree = ""; 286 | }; 287 | EAD5C0652753EDD000CC2766 /* States */ = { 288 | isa = PBXGroup; 289 | children = ( 290 | EAD5C0632753E48400CC2766 /* States.swift */, 291 | ); 292 | path = States; 293 | sourceTree = ""; 294 | }; 295 | EAD5C0662753F23500CC2766 /* UsersModuleTests */ = { 296 | isa = PBXGroup; 297 | children = ( 298 | EAD5C0582753CE8F00CC2766 /* Stubs and Mocks */, 299 | EAD5C05D2753CEC100CC2766 /* UsersUseCaseTests.swift */, 300 | EAD5C05F2753CECE00CC2766 /* UsersViewModelTests.swift */, 301 | ); 302 | path = UsersModuleTests; 303 | sourceTree = ""; 304 | }; 305 | /* End PBXGroup section */ 306 | 307 | /* Begin PBXNativeTarget section */ 308 | EAD5C006275397EE00CC2766 /* MVVM with RxSwift */ = { 309 | isa = PBXNativeTarget; 310 | buildConfigurationList = EAD5C034275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwift" */; 311 | buildPhases = ( 312 | 5A81DC24DD1681F8D46F53F6 /* [CP] Check Pods Manifest.lock */, 313 | EAD5C003275397EE00CC2766 /* Sources */, 314 | EAD5C004275397EE00CC2766 /* Frameworks */, 315 | EAD5C005275397EE00CC2766 /* Resources */, 316 | 042BEDBBFB45D5AE6DA63C12 /* [CP] Embed Pods Frameworks */, 317 | ); 318 | buildRules = ( 319 | ); 320 | dependencies = ( 321 | ); 322 | name = "MVVM with RxSwift"; 323 | productName = "MVVM with RxSwift"; 324 | productReference = EAD5C007275397EE00CC2766 /* MVVM with RxSwift.app */; 325 | productType = "com.apple.product-type.application"; 326 | }; 327 | EAD5C01F275397F100CC2766 /* MVVM with RxSwiftTests */ = { 328 | isa = PBXNativeTarget; 329 | buildConfigurationList = EAD5C037275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwiftTests" */; 330 | buildPhases = ( 331 | AAE4D56B4BD0F0BABDC152BA /* [CP] Check Pods Manifest.lock */, 332 | EAD5C01C275397F100CC2766 /* Sources */, 333 | EAD5C01D275397F100CC2766 /* Frameworks */, 334 | EAD5C01E275397F100CC2766 /* Resources */, 335 | ); 336 | buildRules = ( 337 | ); 338 | dependencies = ( 339 | EAD5C022275397F100CC2766 /* PBXTargetDependency */, 340 | ); 341 | name = "MVVM with RxSwiftTests"; 342 | productName = "MVVM with RxSwiftTests"; 343 | productReference = EAD5C020275397F100CC2766 /* MVVM with RxSwiftTests.xctest */; 344 | productType = "com.apple.product-type.bundle.unit-test"; 345 | }; 346 | EAD5C029275397F100CC2766 /* MVVM with RxSwiftUITests */ = { 347 | isa = PBXNativeTarget; 348 | buildConfigurationList = EAD5C03A275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwiftUITests" */; 349 | buildPhases = ( 350 | BDFF3F4B87CA97A37A863EB3 /* [CP] Check Pods Manifest.lock */, 351 | EAD5C026275397F100CC2766 /* Sources */, 352 | EAD5C027275397F100CC2766 /* Frameworks */, 353 | EAD5C028275397F100CC2766 /* Resources */, 354 | 3D95BAA209DC735C17410F5B /* [CP] Embed Pods Frameworks */, 355 | ); 356 | buildRules = ( 357 | ); 358 | dependencies = ( 359 | EAD5C02C275397F200CC2766 /* PBXTargetDependency */, 360 | ); 361 | name = "MVVM with RxSwiftUITests"; 362 | productName = "MVVM with RxSwiftUITests"; 363 | productReference = EAD5C02A275397F100CC2766 /* MVVM with RxSwiftUITests.xctest */; 364 | productType = "com.apple.product-type.bundle.ui-testing"; 365 | }; 366 | /* End PBXNativeTarget section */ 367 | 368 | /* Begin PBXProject section */ 369 | EAD5BFFF275397EE00CC2766 /* Project object */ = { 370 | isa = PBXProject; 371 | attributes = { 372 | BuildIndependentTargetsInParallel = 1; 373 | LastSwiftUpdateCheck = 1310; 374 | LastUpgradeCheck = 1310; 375 | TargetAttributes = { 376 | EAD5C006275397EE00CC2766 = { 377 | CreatedOnToolsVersion = 13.1; 378 | }; 379 | EAD5C01F275397F100CC2766 = { 380 | CreatedOnToolsVersion = 13.1; 381 | TestTargetID = EAD5C006275397EE00CC2766; 382 | }; 383 | EAD5C029275397F100CC2766 = { 384 | CreatedOnToolsVersion = 13.1; 385 | TestTargetID = EAD5C006275397EE00CC2766; 386 | }; 387 | }; 388 | }; 389 | buildConfigurationList = EAD5C002275397EE00CC2766 /* Build configuration list for PBXProject "MVVM with RxSwift" */; 390 | compatibilityVersion = "Xcode 13.0"; 391 | developmentRegion = en; 392 | hasScannedForEncodings = 0; 393 | knownRegions = ( 394 | en, 395 | Base, 396 | ); 397 | mainGroup = EAD5BFFE275397EE00CC2766; 398 | productRefGroup = EAD5C008275397EE00CC2766 /* Products */; 399 | projectDirPath = ""; 400 | projectRoot = ""; 401 | targets = ( 402 | EAD5C006275397EE00CC2766 /* MVVM with RxSwift */, 403 | EAD5C01F275397F100CC2766 /* MVVM with RxSwiftTests */, 404 | EAD5C029275397F100CC2766 /* MVVM with RxSwiftUITests */, 405 | ); 406 | }; 407 | /* End PBXProject section */ 408 | 409 | /* Begin PBXResourcesBuildPhase section */ 410 | EAD5C005275397EE00CC2766 /* Resources */ = { 411 | isa = PBXResourcesBuildPhase; 412 | buildActionMask = 2147483647; 413 | files = ( 414 | EAD5C01A275397F100CC2766 /* LaunchScreen.storyboard in Resources */, 415 | EAD5C017275397F100CC2766 /* Assets.xcassets in Resources */, 416 | EAD5C012275397EE00CC2766 /* Main.storyboard in Resources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | EAD5C01E275397F100CC2766 /* Resources */ = { 421 | isa = PBXResourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | ); 425 | runOnlyForDeploymentPostprocessing = 0; 426 | }; 427 | EAD5C028275397F100CC2766 /* Resources */ = { 428 | isa = PBXResourcesBuildPhase; 429 | buildActionMask = 2147483647; 430 | files = ( 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | }; 434 | /* End PBXResourcesBuildPhase section */ 435 | 436 | /* Begin PBXShellScriptBuildPhase section */ 437 | 042BEDBBFB45D5AE6DA63C12 /* [CP] Embed Pods Frameworks */ = { 438 | isa = PBXShellScriptBuildPhase; 439 | buildActionMask = 2147483647; 440 | files = ( 441 | ); 442 | inputFileListPaths = ( 443 | "${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift/Pods-MVVM with RxSwift-frameworks-${CONFIGURATION}-input-files.xcfilelist", 444 | ); 445 | name = "[CP] Embed Pods Frameworks"; 446 | outputFileListPaths = ( 447 | "${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift/Pods-MVVM with RxSwift-frameworks-${CONFIGURATION}-output-files.xcfilelist", 448 | ); 449 | runOnlyForDeploymentPostprocessing = 0; 450 | shellPath = /bin/sh; 451 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift/Pods-MVVM with RxSwift-frameworks.sh\"\n"; 452 | showEnvVarsInLog = 0; 453 | }; 454 | 3D95BAA209DC735C17410F5B /* [CP] Embed Pods Frameworks */ = { 455 | isa = PBXShellScriptBuildPhase; 456 | buildActionMask = 2147483647; 457 | files = ( 458 | ); 459 | inputFileListPaths = ( 460 | "${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests-frameworks-${CONFIGURATION}-input-files.xcfilelist", 461 | ); 462 | name = "[CP] Embed Pods Frameworks"; 463 | outputFileListPaths = ( 464 | "${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests-frameworks-${CONFIGURATION}-output-files.xcfilelist", 465 | ); 466 | runOnlyForDeploymentPostprocessing = 0; 467 | shellPath = /bin/sh; 468 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests-frameworks.sh\"\n"; 469 | showEnvVarsInLog = 0; 470 | }; 471 | 5A81DC24DD1681F8D46F53F6 /* [CP] Check Pods Manifest.lock */ = { 472 | isa = PBXShellScriptBuildPhase; 473 | buildActionMask = 2147483647; 474 | files = ( 475 | ); 476 | inputFileListPaths = ( 477 | ); 478 | inputPaths = ( 479 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 480 | "${PODS_ROOT}/Manifest.lock", 481 | ); 482 | name = "[CP] Check Pods Manifest.lock"; 483 | outputFileListPaths = ( 484 | ); 485 | outputPaths = ( 486 | "$(DERIVED_FILE_DIR)/Pods-MVVM with RxSwift-checkManifestLockResult.txt", 487 | ); 488 | runOnlyForDeploymentPostprocessing = 0; 489 | shellPath = /bin/sh; 490 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 491 | showEnvVarsInLog = 0; 492 | }; 493 | AAE4D56B4BD0F0BABDC152BA /* [CP] Check Pods Manifest.lock */ = { 494 | isa = PBXShellScriptBuildPhase; 495 | buildActionMask = 2147483647; 496 | files = ( 497 | ); 498 | inputFileListPaths = ( 499 | ); 500 | inputPaths = ( 501 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 502 | "${PODS_ROOT}/Manifest.lock", 503 | ); 504 | name = "[CP] Check Pods Manifest.lock"; 505 | outputFileListPaths = ( 506 | ); 507 | outputPaths = ( 508 | "$(DERIVED_FILE_DIR)/Pods-MVVM with RxSwiftTests-checkManifestLockResult.txt", 509 | ); 510 | runOnlyForDeploymentPostprocessing = 0; 511 | shellPath = /bin/sh; 512 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 513 | showEnvVarsInLog = 0; 514 | }; 515 | BDFF3F4B87CA97A37A863EB3 /* [CP] Check Pods Manifest.lock */ = { 516 | isa = PBXShellScriptBuildPhase; 517 | buildActionMask = 2147483647; 518 | files = ( 519 | ); 520 | inputFileListPaths = ( 521 | ); 522 | inputPaths = ( 523 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 524 | "${PODS_ROOT}/Manifest.lock", 525 | ); 526 | name = "[CP] Check Pods Manifest.lock"; 527 | outputFileListPaths = ( 528 | ); 529 | outputPaths = ( 530 | "$(DERIVED_FILE_DIR)/Pods-MVVM with RxSwift-MVVM with RxSwiftUITests-checkManifestLockResult.txt", 531 | ); 532 | runOnlyForDeploymentPostprocessing = 0; 533 | shellPath = /bin/sh; 534 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 535 | showEnvVarsInLog = 0; 536 | }; 537 | /* End PBXShellScriptBuildPhase section */ 538 | 539 | /* Begin PBXSourcesBuildPhase section */ 540 | EAD5C003275397EE00CC2766 /* Sources */ = { 541 | isa = PBXSourcesBuildPhase; 542 | buildActionMask = 2147483647; 543 | files = ( 544 | EAD5C04F2753ADAB00CC2766 /* LoadingIndicator+Ext.swift in Sources */, 545 | EAD5C0422753983900CC2766 /* UsersModel.swift in Sources */, 546 | EAD5C04D2753AD9D00CC2766 /* Alerts+Ext.swift in Sources */, 547 | EAD5C0642753E48400CC2766 /* States.swift in Sources */, 548 | EAD5C00F275397EE00CC2766 /* UsersViewController.swift in Sources */, 549 | EAD5C015275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodeld in Sources */, 550 | EAD5C0442753984400CC2766 /* UsersUseCase.swift in Sources */, 551 | EAD5C00B275397EE00CC2766 /* AppDelegate.swift in Sources */, 552 | EAD5C00D275397EE00CC2766 /* SceneDelegate.swift in Sources */, 553 | EAD5C0572753C5BA00CC2766 /* UsersSectionModel.swift in Sources */, 554 | EAD5C0482753990300CC2766 /* UsersViewModel.swift in Sources */, 555 | EAD5C0462753985B00CC2766 /* UsersUseCaseProtocol.swift in Sources */, 556 | ); 557 | runOnlyForDeploymentPostprocessing = 0; 558 | }; 559 | EAD5C01C275397F100CC2766 /* Sources */ = { 560 | isa = PBXSourcesBuildPhase; 561 | buildActionMask = 2147483647; 562 | files = ( 563 | EAD5C05A2753CE9D00CC2766 /* JSONMocking.swift in Sources */, 564 | EAD5C05E2753CEC100CC2766 /* UsersUseCaseTests.swift in Sources */, 565 | EAD5C0602753CECF00CC2766 /* UsersViewModelTests.swift in Sources */, 566 | EAD5C0622753CEE600CC2766 /* StubRequests.swift in Sources */, 567 | EAD5C05C2753CEAB00CC2766 /* UsersUseCaseMock.swift in Sources */, 568 | ); 569 | runOnlyForDeploymentPostprocessing = 0; 570 | }; 571 | EAD5C026275397F100CC2766 /* Sources */ = { 572 | isa = PBXSourcesBuildPhase; 573 | buildActionMask = 2147483647; 574 | files = ( 575 | EAD5C031275397F200CC2766 /* MVVM_with_RxSwiftUITestsLaunchTests.swift in Sources */, 576 | EAD5C02F275397F200CC2766 /* MVVM_with_RxSwiftUITests.swift in Sources */, 577 | ); 578 | runOnlyForDeploymentPostprocessing = 0; 579 | }; 580 | /* End PBXSourcesBuildPhase section */ 581 | 582 | /* Begin PBXTargetDependency section */ 583 | EAD5C022275397F100CC2766 /* PBXTargetDependency */ = { 584 | isa = PBXTargetDependency; 585 | target = EAD5C006275397EE00CC2766 /* MVVM with RxSwift */; 586 | targetProxy = EAD5C021275397F100CC2766 /* PBXContainerItemProxy */; 587 | }; 588 | EAD5C02C275397F200CC2766 /* PBXTargetDependency */ = { 589 | isa = PBXTargetDependency; 590 | target = EAD5C006275397EE00CC2766 /* MVVM with RxSwift */; 591 | targetProxy = EAD5C02B275397F200CC2766 /* PBXContainerItemProxy */; 592 | }; 593 | /* End PBXTargetDependency section */ 594 | 595 | /* Begin PBXVariantGroup section */ 596 | EAD5C010275397EE00CC2766 /* Main.storyboard */ = { 597 | isa = PBXVariantGroup; 598 | children = ( 599 | EAD5C011275397EE00CC2766 /* Base */, 600 | ); 601 | name = Main.storyboard; 602 | sourceTree = ""; 603 | }; 604 | EAD5C018275397F100CC2766 /* LaunchScreen.storyboard */ = { 605 | isa = PBXVariantGroup; 606 | children = ( 607 | EAD5C019275397F100CC2766 /* Base */, 608 | ); 609 | name = LaunchScreen.storyboard; 610 | sourceTree = ""; 611 | }; 612 | /* End PBXVariantGroup section */ 613 | 614 | /* Begin XCBuildConfiguration section */ 615 | EAD5C032275397F200CC2766 /* Debug */ = { 616 | isa = XCBuildConfiguration; 617 | buildSettings = { 618 | ALWAYS_SEARCH_USER_PATHS = NO; 619 | CLANG_ANALYZER_NONNULL = YES; 620 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 621 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 622 | CLANG_CXX_LIBRARY = "libc++"; 623 | CLANG_ENABLE_MODULES = YES; 624 | CLANG_ENABLE_OBJC_ARC = YES; 625 | CLANG_ENABLE_OBJC_WEAK = YES; 626 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 627 | CLANG_WARN_BOOL_CONVERSION = YES; 628 | CLANG_WARN_COMMA = YES; 629 | CLANG_WARN_CONSTANT_CONVERSION = YES; 630 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 631 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 632 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 633 | CLANG_WARN_EMPTY_BODY = YES; 634 | CLANG_WARN_ENUM_CONVERSION = YES; 635 | CLANG_WARN_INFINITE_RECURSION = YES; 636 | CLANG_WARN_INT_CONVERSION = YES; 637 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 638 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 639 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 640 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 641 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 642 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 643 | CLANG_WARN_STRICT_PROTOTYPES = YES; 644 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 645 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 646 | CLANG_WARN_UNREACHABLE_CODE = YES; 647 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 648 | COPY_PHASE_STRIP = NO; 649 | DEBUG_INFORMATION_FORMAT = dwarf; 650 | ENABLE_STRICT_OBJC_MSGSEND = YES; 651 | ENABLE_TESTABILITY = YES; 652 | GCC_C_LANGUAGE_STANDARD = gnu11; 653 | GCC_DYNAMIC_NO_PIC = NO; 654 | GCC_NO_COMMON_BLOCKS = YES; 655 | GCC_OPTIMIZATION_LEVEL = 0; 656 | GCC_PREPROCESSOR_DEFINITIONS = ( 657 | "DEBUG=1", 658 | "$(inherited)", 659 | ); 660 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 661 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 662 | GCC_WARN_UNDECLARED_SELECTOR = YES; 663 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 664 | GCC_WARN_UNUSED_FUNCTION = YES; 665 | GCC_WARN_UNUSED_VARIABLE = YES; 666 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 667 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 668 | MTL_FAST_MATH = YES; 669 | ONLY_ACTIVE_ARCH = YES; 670 | SDKROOT = iphoneos; 671 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 672 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 673 | }; 674 | name = Debug; 675 | }; 676 | EAD5C033275397F200CC2766 /* Release */ = { 677 | isa = XCBuildConfiguration; 678 | buildSettings = { 679 | ALWAYS_SEARCH_USER_PATHS = NO; 680 | CLANG_ANALYZER_NONNULL = YES; 681 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 682 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 683 | CLANG_CXX_LIBRARY = "libc++"; 684 | CLANG_ENABLE_MODULES = YES; 685 | CLANG_ENABLE_OBJC_ARC = YES; 686 | CLANG_ENABLE_OBJC_WEAK = YES; 687 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 688 | CLANG_WARN_BOOL_CONVERSION = YES; 689 | CLANG_WARN_COMMA = YES; 690 | CLANG_WARN_CONSTANT_CONVERSION = YES; 691 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 692 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 693 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 694 | CLANG_WARN_EMPTY_BODY = YES; 695 | CLANG_WARN_ENUM_CONVERSION = YES; 696 | CLANG_WARN_INFINITE_RECURSION = YES; 697 | CLANG_WARN_INT_CONVERSION = YES; 698 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 699 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 700 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 701 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 702 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 703 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 704 | CLANG_WARN_STRICT_PROTOTYPES = YES; 705 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 706 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 707 | CLANG_WARN_UNREACHABLE_CODE = YES; 708 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 709 | COPY_PHASE_STRIP = NO; 710 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 711 | ENABLE_NS_ASSERTIONS = NO; 712 | ENABLE_STRICT_OBJC_MSGSEND = YES; 713 | GCC_C_LANGUAGE_STANDARD = gnu11; 714 | GCC_NO_COMMON_BLOCKS = YES; 715 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 716 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 717 | GCC_WARN_UNDECLARED_SELECTOR = YES; 718 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 719 | GCC_WARN_UNUSED_FUNCTION = YES; 720 | GCC_WARN_UNUSED_VARIABLE = YES; 721 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 722 | MTL_ENABLE_DEBUG_INFO = NO; 723 | MTL_FAST_MATH = YES; 724 | SDKROOT = iphoneos; 725 | SWIFT_COMPILATION_MODE = wholemodule; 726 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 727 | VALIDATE_PRODUCT = YES; 728 | }; 729 | name = Release; 730 | }; 731 | EAD5C035275397F200CC2766 /* Debug */ = { 732 | isa = XCBuildConfiguration; 733 | baseConfigurationReference = 0388C88983F05A45E555A5BD /* Pods-MVVM with RxSwift.debug.xcconfig */; 734 | buildSettings = { 735 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 736 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 737 | CODE_SIGN_STYLE = Automatic; 738 | CURRENT_PROJECT_VERSION = 1; 739 | DEVELOPMENT_TEAM = H368HQSP2D; 740 | GENERATE_INFOPLIST_FILE = YES; 741 | INFOPLIST_FILE = "MVVM with RxSwift/Info.plist"; 742 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 743 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 744 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 745 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 746 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 747 | LD_RUNPATH_SEARCH_PATHS = ( 748 | "$(inherited)", 749 | "@executable_path/Frameworks", 750 | ); 751 | MARKETING_VERSION = 1.0; 752 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwift"; 753 | PRODUCT_NAME = "$(TARGET_NAME)"; 754 | SWIFT_EMIT_LOC_STRINGS = YES; 755 | SWIFT_VERSION = 5.0; 756 | TARGETED_DEVICE_FAMILY = "1,2"; 757 | }; 758 | name = Debug; 759 | }; 760 | EAD5C036275397F200CC2766 /* Release */ = { 761 | isa = XCBuildConfiguration; 762 | baseConfigurationReference = A5BE4870BBC3A803270463C8 /* Pods-MVVM with RxSwift.release.xcconfig */; 763 | buildSettings = { 764 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 765 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 766 | CODE_SIGN_STYLE = Automatic; 767 | CURRENT_PROJECT_VERSION = 1; 768 | DEVELOPMENT_TEAM = H368HQSP2D; 769 | GENERATE_INFOPLIST_FILE = YES; 770 | INFOPLIST_FILE = "MVVM with RxSwift/Info.plist"; 771 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 772 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; 773 | INFOPLIST_KEY_UIMainStoryboardFile = Main; 774 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 775 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 776 | LD_RUNPATH_SEARCH_PATHS = ( 777 | "$(inherited)", 778 | "@executable_path/Frameworks", 779 | ); 780 | MARKETING_VERSION = 1.0; 781 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwift"; 782 | PRODUCT_NAME = "$(TARGET_NAME)"; 783 | SWIFT_EMIT_LOC_STRINGS = YES; 784 | SWIFT_VERSION = 5.0; 785 | TARGETED_DEVICE_FAMILY = "1,2"; 786 | }; 787 | name = Release; 788 | }; 789 | EAD5C038275397F200CC2766 /* Debug */ = { 790 | isa = XCBuildConfiguration; 791 | baseConfigurationReference = C137A675521ACEBAA19DAF49 /* Pods-MVVM with RxSwiftTests.debug.xcconfig */; 792 | buildSettings = { 793 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 794 | BUNDLE_LOADER = "$(TEST_HOST)"; 795 | CODE_SIGN_STYLE = Automatic; 796 | CURRENT_PROJECT_VERSION = 1; 797 | DEVELOPMENT_TEAM = H368HQSP2D; 798 | GENERATE_INFOPLIST_FILE = YES; 799 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 800 | LD_RUNPATH_SEARCH_PATHS = ( 801 | "$(inherited)", 802 | "@executable_path/Frameworks", 803 | "@loader_path/Frameworks", 804 | ); 805 | MARKETING_VERSION = 1.0; 806 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwiftTests"; 807 | PRODUCT_NAME = "$(TARGET_NAME)"; 808 | SWIFT_EMIT_LOC_STRINGS = NO; 809 | SWIFT_VERSION = 5.0; 810 | TARGETED_DEVICE_FAMILY = "1,2"; 811 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MVVM with RxSwift.app/MVVM with RxSwift"; 812 | }; 813 | name = Debug; 814 | }; 815 | EAD5C039275397F200CC2766 /* Release */ = { 816 | isa = XCBuildConfiguration; 817 | baseConfigurationReference = 82C2250A6F207AD6E4F7E033 /* Pods-MVVM with RxSwiftTests.release.xcconfig */; 818 | buildSettings = { 819 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 820 | BUNDLE_LOADER = "$(TEST_HOST)"; 821 | CODE_SIGN_STYLE = Automatic; 822 | CURRENT_PROJECT_VERSION = 1; 823 | DEVELOPMENT_TEAM = H368HQSP2D; 824 | GENERATE_INFOPLIST_FILE = YES; 825 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 826 | LD_RUNPATH_SEARCH_PATHS = ( 827 | "$(inherited)", 828 | "@executable_path/Frameworks", 829 | "@loader_path/Frameworks", 830 | ); 831 | MARKETING_VERSION = 1.0; 832 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwiftTests"; 833 | PRODUCT_NAME = "$(TARGET_NAME)"; 834 | SWIFT_EMIT_LOC_STRINGS = NO; 835 | SWIFT_VERSION = 5.0; 836 | TARGETED_DEVICE_FAMILY = "1,2"; 837 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MVVM with RxSwift.app/MVVM with RxSwift"; 838 | }; 839 | name = Release; 840 | }; 841 | EAD5C03B275397F200CC2766 /* Debug */ = { 842 | isa = XCBuildConfiguration; 843 | baseConfigurationReference = 45041708CCBF800C159CB7C3 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.debug.xcconfig */; 844 | buildSettings = { 845 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 846 | CODE_SIGN_STYLE = Automatic; 847 | CURRENT_PROJECT_VERSION = 1; 848 | DEVELOPMENT_TEAM = H368HQSP2D; 849 | GENERATE_INFOPLIST_FILE = YES; 850 | LD_RUNPATH_SEARCH_PATHS = ( 851 | "$(inherited)", 852 | "@executable_path/Frameworks", 853 | "@loader_path/Frameworks", 854 | ); 855 | MARKETING_VERSION = 1.0; 856 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwiftUITests"; 857 | PRODUCT_NAME = "$(TARGET_NAME)"; 858 | SWIFT_EMIT_LOC_STRINGS = NO; 859 | SWIFT_VERSION = 5.0; 860 | TARGETED_DEVICE_FAMILY = "1,2"; 861 | TEST_TARGET_NAME = "MVVM with RxSwift"; 862 | }; 863 | name = Debug; 864 | }; 865 | EAD5C03C275397F200CC2766 /* Release */ = { 866 | isa = XCBuildConfiguration; 867 | baseConfigurationReference = ADF09A289472C810D4DFD134 /* Pods-MVVM with RxSwift-MVVM with RxSwiftUITests.release.xcconfig */; 868 | buildSettings = { 869 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 870 | CODE_SIGN_STYLE = Automatic; 871 | CURRENT_PROJECT_VERSION = 1; 872 | DEVELOPMENT_TEAM = H368HQSP2D; 873 | GENERATE_INFOPLIST_FILE = YES; 874 | LD_RUNPATH_SEARCH_PATHS = ( 875 | "$(inherited)", 876 | "@executable_path/Frameworks", 877 | "@loader_path/Frameworks", 878 | ); 879 | MARKETING_VERSION = 1.0; 880 | PRODUCT_BUNDLE_IDENTIFIER = "com.product.MVVM-with-RxSwiftUITests"; 881 | PRODUCT_NAME = "$(TARGET_NAME)"; 882 | SWIFT_EMIT_LOC_STRINGS = NO; 883 | SWIFT_VERSION = 5.0; 884 | TARGETED_DEVICE_FAMILY = "1,2"; 885 | TEST_TARGET_NAME = "MVVM with RxSwift"; 886 | }; 887 | name = Release; 888 | }; 889 | /* End XCBuildConfiguration section */ 890 | 891 | /* Begin XCConfigurationList section */ 892 | EAD5C002275397EE00CC2766 /* Build configuration list for PBXProject "MVVM with RxSwift" */ = { 893 | isa = XCConfigurationList; 894 | buildConfigurations = ( 895 | EAD5C032275397F200CC2766 /* Debug */, 896 | EAD5C033275397F200CC2766 /* Release */, 897 | ); 898 | defaultConfigurationIsVisible = 0; 899 | defaultConfigurationName = Release; 900 | }; 901 | EAD5C034275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwift" */ = { 902 | isa = XCConfigurationList; 903 | buildConfigurations = ( 904 | EAD5C035275397F200CC2766 /* Debug */, 905 | EAD5C036275397F200CC2766 /* Release */, 906 | ); 907 | defaultConfigurationIsVisible = 0; 908 | defaultConfigurationName = Release; 909 | }; 910 | EAD5C037275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwiftTests" */ = { 911 | isa = XCConfigurationList; 912 | buildConfigurations = ( 913 | EAD5C038275397F200CC2766 /* Debug */, 914 | EAD5C039275397F200CC2766 /* Release */, 915 | ); 916 | defaultConfigurationIsVisible = 0; 917 | defaultConfigurationName = Release; 918 | }; 919 | EAD5C03A275397F200CC2766 /* Build configuration list for PBXNativeTarget "MVVM with RxSwiftUITests" */ = { 920 | isa = XCConfigurationList; 921 | buildConfigurations = ( 922 | EAD5C03B275397F200CC2766 /* Debug */, 923 | EAD5C03C275397F200CC2766 /* Release */, 924 | ); 925 | defaultConfigurationIsVisible = 0; 926 | defaultConfigurationName = Release; 927 | }; 928 | /* End XCConfigurationList section */ 929 | 930 | /* Begin XCVersionGroup section */ 931 | EAD5C013275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodeld */ = { 932 | isa = XCVersionGroup; 933 | children = ( 934 | EAD5C014275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodel */, 935 | ); 936 | currentVersion = EAD5C014275397EE00CC2766 /* MVVM_with_RxSwift.xcdatamodel */; 937 | path = MVVM_with_RxSwift.xcdatamodeld; 938 | sourceTree = ""; 939 | versionGroupType = wrapper.xcdatamodel; 940 | }; 941 | /* End XCVersionGroup section */ 942 | }; 943 | rootObject = EAD5BFFF275397EE00CC2766 /* Project object */; 944 | } 945 | --------------------------------------------------------------------------------