├── .gitignore
├── RxSwiftMVVM
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Resource
│ └── Marvel_logo.jpg
├── Const
│ └── AppDefinition.swift
├── Extension
│ └── ObservableType-Extension.swift
├── Navigator
│ └── MarvelSearchNavigator.swift
├── NavigationController.swift
├── Model
│ └── MarvelHeroModel.swift
├── ViewModel
│ ├── MarvelSearchTVCellViewModel.swift
│ ├── MarvelSearchViewModel.swift
│ └── MarvelDescriptionViewModel.swift
├── ViewController.swift
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── Service
│ └── MarvelService.swift
├── AppDelegate.swift
├── View
│ └── MarvelSearchTVCell.swift
└── ViewController
│ ├── MarvelSearchVC.swift
│ └── MarvelDescriptionVC.swift
├── Podfile
├── RxSwiftMVVM.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LICENSE
├── Podfile.lock
├── README.md
└── RxSwiftMVVM.xcodeproj
└── project.pbxproj
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.xcuserstate
3 | project.xcworkspace/
4 | xcuserdata/
5 |
6 | Pods/
--------------------------------------------------------------------------------
/RxSwiftMVVM/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/RxSwiftMVVM/Resource/Marvel_logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dokgi88/rxswift-mvvm-example/HEAD/RxSwiftMVVM/Resource/Marvel_logo.jpg
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'RxSwiftMVVM' do
4 | pod 'RxSwift', '~> 4.0'
5 | pod 'RxCocoa', '~> 4.0'
6 | pod 'SwiftyJSON', '~> 4.0'
7 | pod 'Then'
8 | pod 'Alamofire'
9 | pod 'Kingfisher'
10 | pod 'CryptoSwift'
11 | pod 'Result', '~> 4.0.0'
12 | end
13 |
--------------------------------------------------------------------------------
/RxSwiftMVVM.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/RxSwiftMVVM.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Const/AppDefinition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDefinition.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by cashwalk on 13/12/2018.
6 | // Copyright © 2018 cashwalk. All rights reserved.
7 | //
8 |
9 | let MARVEL_API = "https://gateway.marvel.com/"
10 | let MARVEL_API_CHARACTERS = "v1/public/characters"
11 |
12 | let MARVEL_PUBLIC_KEY = "0fb4a9b7adfe6ecc0df9de15a983989a"
13 | let MARVEL_PRIVATE_KEY = "87f2630587cd5e08c144d503c6742c6b6e6e91a0"
14 |
15 | let MARVEL_HERO_KEY = "MARVEL_HERO_KEY"
16 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Extension/ObservableType-Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ObservableType-Extension.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 07/04/2019.
6 | // Copyright © 2019 cashwalk. All rights reserved.
7 | //
8 |
9 | import RxCocoa
10 | import RxSwift
11 |
12 | extension ObservableType {
13 |
14 | func asDriverComplete() -> SharedSequence {
15 | return asDriver(onErrorRecover: { (error) in
16 | return Driver.empty()
17 | })
18 | }
19 |
20 | func mapToVoid() -> Observable {
21 | return map { _ in }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Navigator/MarvelSearchNavigator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelSearchNavigator.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 07/04/2019.
6 | //
7 |
8 | import UIKit
9 |
10 | final class MarvelSearchNavigator {
11 |
12 | private let navigationController: UINavigationController?
13 |
14 | init(_ navigationController: UINavigationController?) {
15 | self.navigationController = navigationController
16 | }
17 |
18 | // MARK: - Internal Method
19 |
20 | func showDescription(model: MarvelHeroModel) {
21 | let controller = MarvelDescriptionVC(viewModel: .init(model: model))
22 | navigationController?.show(controller, sender: nil)
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/NavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationController.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 07/04/2019.
6 | //
7 |
8 | import UIKit
9 |
10 | class NavigationController: UINavigationController {
11 |
12 | override func viewDidLoad() {
13 | super.viewDidLoad()
14 |
15 | let logoView = UIImageView(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
16 | logoView.image = UIImage(named: "Marvel_logo.jpg")
17 | logoView.contentMode = .scaleAspectFit
18 |
19 | navigationBar.tintColor = .white
20 | navigationBar.barTintColor = .black
21 | navigationBar.topItem?.titleView = logoView
22 | navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
23 | navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 dokgi88
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Model/MarvelHeroModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelHeroModel.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import SwiftyJSON
9 |
10 | class MarvelHeroModel {
11 |
12 | private(set) var name: String?
13 | private(set) var description: String?
14 | private(set) var thumbnail: String?
15 |
16 | init(json: JSON) {
17 | name = json["name"].string
18 | description = json["description"].string
19 | if let dicThumnail = json["thumbnail"].dictionary {
20 | guard let path = dicThumnail["path"]?.string else {return}
21 | guard let thumbnailEx = dicThumnail["extension"]?.string else {return}
22 | thumbnail = "\(path).\(thumbnailEx)"
23 | }
24 | }
25 | }
26 |
27 | struct MarvelHeroData: Decodable {
28 | let data: MarvelHeroResult
29 | }
30 |
31 | struct MarvelHeroResult: Decodable {
32 | let results: [HeroModel]
33 | }
34 |
35 | struct HeroModel: Decodable {
36 | let name: String
37 | let description: String
38 | let thumbnail: HeroThumbnail
39 | }
40 |
41 | struct HeroThumbnail: Decodable {
42 | let path: String
43 | let `extension`: String
44 | }
45 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (4.8.0)
3 | - CryptoSwift (0.13.1)
4 | - Kingfisher (5.0.0)
5 | - Result (4.0.1)
6 | - RxAtomic (4.4.0)
7 | - RxCocoa (4.4.0):
8 | - RxSwift (~> 4.0)
9 | - RxSwift (4.4.0):
10 | - RxAtomic (~> 4.4)
11 | - SwiftyJSON (4.2.0)
12 | - Then (2.4.0)
13 |
14 | DEPENDENCIES:
15 | - Alamofire
16 | - CryptoSwift
17 | - Kingfisher
18 | - Result (~> 4.0.0)
19 | - RxCocoa (~> 4.0)
20 | - RxSwift (~> 4.0)
21 | - SwiftyJSON (~> 4.0)
22 | - Then
23 |
24 | SPEC REPOS:
25 | https://github.com/cocoapods/specs.git:
26 | - Alamofire
27 | - CryptoSwift
28 | - Kingfisher
29 | - Result
30 | - RxAtomic
31 | - RxCocoa
32 | - RxSwift
33 | - SwiftyJSON
34 | - Then
35 |
36 | SPEC CHECKSUMS:
37 | Alamofire: 3ec537f71edc9804815215393ae2b1a8ea33a844
38 | CryptoSwift: ff68c35a53e03177d31aaa2c1e8b3e010aeed6cb
39 | Kingfisher: 2b0dd651e4fe5a07305b8242fde56f8e2d410f58
40 | Result: a6e784bebf48b471d59cddc1adb81f41f678c487
41 | RxAtomic: eacf60db868c96bfd63320e28619fe29c179656f
42 | RxCocoa: df63ebf7b9a70d6b4eeea407ed5dd4efc8979749
43 | RxSwift: 5976ecd04fc2fefd648827c23de5e11157faa973
44 | SwiftyJSON: c4bcba26dd9ec7a027fc8eade48e2c911f229e96
45 | Then: 71866660c7af35a7343831f7668e7cd2b62ee0f2
46 |
47 | PODFILE CHECKSUM: 38af498490a4857a1955491e50555af89801c852
48 |
49 | COCOAPODS: 1.5.2
50 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewModel/MarvelSearchTVCellViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelSearchTVCellViewModel.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 07/04/2019.
6 | //
7 |
8 | import RxCocoa
9 | import RxSwift
10 |
11 | final class MarvelSearchTVCellViewModel {
12 |
13 | let model: MarvelHeroModel
14 |
15 | init(model: MarvelHeroModel) {
16 | self.model = model
17 | }
18 |
19 | struct Input {
20 | let trigger: Driver
21 | }
22 | struct Output {
23 | let name: Driver
24 | let thumbnail: Driver
25 | }
26 |
27 | // MARK: - Internal Method
28 |
29 | func transform(input: Input) -> Output {
30 | let name: Driver = input.trigger
31 | .flatMapLatest { [weak self] (_) in
32 | guard let self = self, let name = self.model.name else {return Driver.empty()}
33 | return Driver.just(name)
34 | }
35 | let thumbnail: Driver = input.trigger
36 | .flatMapLatest { [weak self] (_) in
37 | guard let self = self else {return Driver.empty()}
38 | guard let thumnail = self.model.thumbnail, let url = URL(string: thumnail) else {return Driver.empty()}
39 | return Driver.just(url)
40 | }
41 |
42 | return Output(name: name, thumbnail: thumbnail)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RxSwift MVVM example
2 |
3 | 
4 | [](https://raw.githubusercontent.com/dokgi88/rxswift-mvvm-example/master/LICENSE)
5 |
6 | Marvel API example with MVVM Architecture pattern using RxSwift.
7 | [Clean Architecture](https://github.com/sergdort/CleanArchitectureRxSwift) partial application
8 |
9 | ## Example
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ## Getting Started
20 |
21 | 1. run pod install
22 | ```console
23 | $ pod install
24 | ```
25 |
26 | 2. open RxSwiftMVVM.xcworkspace
27 | ```console
28 | $ open RxSwiftMVVM.xcworkspace
29 | ```
30 |
31 | 3. run RxSwiftMVVM
32 |
33 |
34 | ## LICENSE
35 |
36 | These works are available under the MIT license. See the [LICENSE][license] file
37 | for more info.
38 |
39 | [license]: LICENSE
40 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 13/12/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | class ViewController: UIViewController {
11 |
12 | private let indicatorView = UIActivityIndicatorView().then {
13 | $0.translatesAutoresizingMaskIntoConstraints = false
14 | $0.style = .whiteLarge
15 | $0.backgroundColor = UIColor.black.withAlphaComponent(0.5)
16 | $0.startAnimating()
17 | $0.alpha = 0
18 | }
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | setProperties()
24 | }
25 |
26 | public func setTitle(_ text: String) {
27 | title = text
28 | }
29 |
30 | public func showLoading() {
31 | view.addSubview(indicatorView)
32 |
33 | indicatorView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
34 | indicatorView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
35 | indicatorView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
36 | indicatorView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
37 |
38 | indicatorView.alpha = 1
39 | }
40 |
41 | public func hideLoading() {
42 | indicatorView.alpha = 0
43 |
44 | indicatorView.removeFromSuperview()
45 | }
46 |
47 | private func getClassName(_ anyClass: AnyObject) -> String {
48 | return String(describing: type(of: anyClass))
49 | }
50 |
51 | private func setProperties() {
52 | view.backgroundColor = .black
53 | }
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/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 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | NSAppTransportSecurity
45 |
46 | NSAllowsArbitraryLoads
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewModel/MarvelSearchViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelSearchViewModel.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import RxCocoa
9 | import RxSwift
10 |
11 | final class MarvelSearchViewModel {
12 |
13 | // MARK: - Properties
14 |
15 | private var disposeBag = DisposeBag()
16 | private var heros = PublishRelay<[MarvelHeroModel]>()
17 | private let navigator: MarvelSearchNavigator
18 |
19 | init(navigator: MarvelSearchNavigator) {
20 | self.navigator = navigator
21 | }
22 |
23 | struct Input {
24 | let searchText: Driver
25 | let modelSelected: ControlEvent
26 | }
27 | struct Output {
28 | let heros: Observable<[MarvelHeroModel]>
29 | }
30 |
31 | // MARK: - Internal methods
32 |
33 | func transform(input: Input) -> Output {
34 | input.searchText
35 | .drive(onNext: { [weak self] (searchText) in
36 | guard let self = self else {return}
37 | self.requestHero(searchText: searchText)
38 | })
39 | .disposed(by: disposeBag)
40 | input.modelSelected
41 | .bind { [weak self] (model) in
42 | guard let self = self else {return}
43 | self.navigator.showDescription(model: model)
44 | }
45 | .disposed(by: disposeBag)
46 |
47 | return Output(heros: heros.asObservable())
48 | }
49 |
50 | // MARK: - Private Method
51 |
52 | private func requestHero(searchText: String) {
53 | MarvelService().getCharacters(name: searchText, offset: 20) { [weak self] (error, result) in
54 | guard let self = self else {return}
55 | guard error == nil, let result = result, result.count > 0 else {return self.heros.accept([])}
56 | self.heros.accept(result)
57 | }
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Service/MarvelService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelService.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import Alamofire
9 | import CryptoSwift
10 | import RxCocoa
11 | import SwiftyJSON
12 |
13 | class MarvelService {
14 |
15 | @discardableResult
16 | public func getCharacters(name: String, offset: Int, completion: @escaping (NSError?, [MarvelHeroModel]?) -> Void) -> URLSessionTask? {
17 |
18 | let url = "\(MARVEL_API)\(MARVEL_API_CHARACTERS)"
19 | var param = [String: Any]()
20 | let timeStamp = Int(Date().timeIntervalSince1970)
21 | param["ts"] = timeStamp
22 | param["apikey"] = MARVEL_PUBLIC_KEY
23 | param["hash"] = getHash(ts: timeStamp)
24 | if name.count > 0 {
25 | param["nameStartsWith"] = name
26 | }
27 | param["limit"] = 20
28 | param["offset"] = offset
29 | let headers = ["Content-Type":"application/json", "Accept":"application/json"]
30 |
31 | return Alamofire.request(url, method: HTTPMethod.get, parameters: param, encoding: URLEncoding.default, headers: headers).responseJSON { (response) in
32 |
33 | switch response.result {
34 | case .success(let value):
35 | let json = JSON(value)
36 | let error = json["error"]
37 | guard error.isEmpty else {return}
38 | guard let data = json["data"].dictionary else {return}
39 | guard let result = data["results"]?.array else {return}
40 |
41 | completion(nil, result.compactMap({MarvelHeroModel(json: $0)}))
42 | case .failure(let error):
43 | completion(error as NSError, nil)
44 | }
45 | }.task
46 | }
47 |
48 | private func getHash(ts: Int) -> String {
49 | let hash = "\(ts)\(MARVEL_PRIVATE_KEY)\(MARVEL_PUBLIC_KEY)"
50 | return hash.md5()
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/RxSwiftMVVM/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by cashwalk on 13/12/2018.
6 | // Copyright © 2018 cashwalk. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
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 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewModel/MarvelDescriptionViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelDescriptionViewModel.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import RxCocoa
9 | import RxSwift
10 |
11 | final class MarvelDescriptionViewModel {
12 |
13 | private let model: MarvelHeroModel
14 |
15 | init(model: MarvelHeroModel) {
16 | self.model = model
17 | }
18 |
19 | struct Input {
20 | let trigger: Driver
21 | }
22 | struct Output {
23 | let thumbnail: Driver
24 | let name: Driver
25 | let description: Driver
26 | }
27 |
28 | // MARK: - Internal Method
29 |
30 | func transform(input: Input) -> Output {
31 | let thumbnail: Driver = input.trigger
32 | .flatMapLatest { [weak self] (_) in
33 | guard let self = self else {return Driver.empty()}
34 | guard let thumbnail = self.model.thumbnail, let url = URL(string: thumbnail) else {return Driver.empty()}
35 | return Driver.just(url)
36 | }
37 | let name: Driver = input.trigger
38 | .flatMapLatest { [weak self] (_) in
39 | guard let self = self, let name = self.model.name else {return Driver.empty()}
40 | return Driver.just(name)
41 | }
42 | let description: Driver = input.trigger
43 | .flatMapLatest { [weak self] (_) in
44 | guard let self = self else {return Driver.empty()}
45 | return Driver.just(self.getDescription())
46 | }
47 |
48 | return Output(thumbnail: thumbnail, name: name, description: description)
49 | }
50 |
51 | // MARK: - Private Method
52 |
53 | private func getDescription() -> NSAttributedString {
54 | guard let name = model.name, let desc = model.description else {return NSAttributedString(string: "Not Description")}
55 | let description = desc.count > 0 ? desc:"Not Description"
56 | let originText = "\(name)\n\n\(description)"
57 | let range = originText.lowercased().range(of: name.lowercased())
58 | let attributeString = NSMutableAttributedString(string: originText,
59 | attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16, weight: .semibold), NSAttributedString.Key.foregroundColor:UIColor.black])
60 | attributeString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 30, weight: .black), range: NSRange(location: (range?.lowerBound.encodedOffset)!, length: name.count))
61 | return attributeString
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/View/MarvelSearchTVCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelSearchTVCell.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import UIKit
9 |
10 | import Kingfisher
11 | import RxCocoa
12 | import RxSwift
13 | import Then
14 |
15 | class MarvelSearchTVCell: UITableViewCell {
16 |
17 | // MARK: - Constants
18 |
19 | static let reuseIdentifier = "MarvelSearchTVCell"
20 |
21 | // MARK: - Properties
22 |
23 | private var disposeBag = DisposeBag()
24 | private var viewModel: MarvelSearchTVCellViewModel!
25 |
26 | // MARK: - UI Components
27 |
28 | private let heroImageView = UIImageView().then {
29 | $0.translatesAutoresizingMaskIntoConstraints = false
30 | $0.contentMode = .scaleAspectFill
31 | $0.layer.cornerRadius = 6
32 | $0.clipsToBounds = true
33 | }
34 | private let heroTitleLabel = UILabel().then {
35 | $0.translatesAutoresizingMaskIntoConstraints = false
36 | $0.backgroundColor = UIColor.black.withAlphaComponent(0.5)
37 | $0.font = .systemFont(ofSize: 20, weight: .black)
38 | $0.textColor = .white
39 | $0.textAlignment = .center
40 | }
41 |
42 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
43 | super.init(style: style, reuseIdentifier: reuseIdentifier)
44 |
45 | setProperties()
46 | contentView.addSubview(heroImageView)
47 | contentView.addSubview(heroTitleLabel)
48 | layout()
49 | }
50 |
51 | required init?(coder aDecoder: NSCoder) {
52 | fatalError("init(coder:) has not been implemented")
53 | }
54 |
55 | override func prepareForReuse() {
56 | heroImageView.image = nil
57 | heroTitleLabel.text = nil
58 | }
59 |
60 | func configure(viewModel: MarvelSearchTVCellViewModel) {
61 | self.viewModel = viewModel
62 | bindViewModel()
63 | }
64 |
65 | private func bindViewModel() {
66 | let layoutSubviews = rx.sentMessage(#selector(UITableViewCell.layoutSubviews)).take(1).mapToVoid().asDriverComplete()
67 | let input = MarvelSearchTVCellViewModel.Input(trigger: layoutSubviews)
68 |
69 | let output = viewModel.transform(input: input)
70 | output.thumbnail
71 | .drive(onNext: { [weak self] (url) in
72 | guard let self = self else {return}
73 | self.heroImageView.kf.setImage(with: url)
74 | })
75 | .disposed(by: disposeBag)
76 | output.name
77 | .drive(heroTitleLabel.rx.text)
78 | .disposed(by: disposeBag)
79 | }
80 |
81 | private func setProperties() {
82 | backgroundColor = .clear
83 | selectionStyle = .none
84 | }
85 | }
86 |
87 | // MARK: - Layout
88 |
89 | extension MarvelSearchTVCell {
90 |
91 | private func layout() {
92 | heroImageView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
93 | heroImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
94 | heroImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
95 | heroImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
96 |
97 | heroTitleLabel.topAnchor.constraint(equalTo: heroImageView.topAnchor).isActive = true
98 | heroTitleLabel.leadingAnchor.constraint(equalTo: heroImageView.leadingAnchor).isActive = true
99 | heroTitleLabel.trailingAnchor.constraint(equalTo: heroImageView.trailingAnchor).isActive = true
100 | heroTitleLabel.bottomAnchor.constraint(equalTo: heroImageView.bottomAnchor).isActive = true
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/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 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewController/MarvelSearchVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelSearchVC.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import RxCocoa
9 | import RxSwift
10 |
11 | final class MarvelSearchVC: ViewController {
12 |
13 | // MARK: - Properties
14 |
15 | private let disposeBag = DisposeBag()
16 | private var searchText = PublishRelay()
17 | private lazy var viewModel = MarvelSearchViewModel(navigator: .init(self.navigationController))
18 |
19 | // MARK: - UI Components
20 |
21 | private let searchTextField = UITextField().then {
22 | let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: 48))
23 | $0.leftView = paddingView
24 | $0.leftViewMode = .always
25 | $0.translatesAutoresizingMaskIntoConstraints = false
26 | $0.borderStyle = UITextField.BorderStyle.roundedRect
27 | $0.placeholder = "ex. Spider-Man"
28 | $0.backgroundColor = .white
29 | }
30 | private let tableView = UITableView(frame: .zero, style: .plain).then {
31 | $0.translatesAutoresizingMaskIntoConstraints = false
32 | }
33 | private let emptyLabel = UILabel().then {
34 | $0.translatesAutoresizingMaskIntoConstraints = false
35 | $0.backgroundColor = .black
36 | $0.text = "no heros :("
37 | $0.textColor = .white
38 | $0.textAlignment = .center
39 | $0.font = .boldSystemFont(ofSize: 30)
40 | $0.isHidden = false
41 | }
42 |
43 | // MARK: - Overridden: BackViewController
44 |
45 | override func viewDidLoad() {
46 | super.viewDidLoad()
47 |
48 | bindView()
49 | bindViewModel()
50 | setProperties()
51 | setupUI()
52 | }
53 |
54 | // MARK: - Private methods
55 |
56 | private func bindView() {
57 | searchTextField.rx.controlEvent(.editingDidEndOnExit)
58 | .bind { [weak self] (event) in
59 | guard let self = self, let text = self.searchTextField.text else {return}
60 |
61 | self.showLoading()
62 | UIView.animate(withDuration: 0.3, animations: {
63 | self.tableView.contentOffset = .zero
64 | }, completion: { (_) in
65 | self.searchText.accept(text)
66 | })
67 | }
68 | .disposed(by: disposeBag)
69 | }
70 |
71 | private func bindViewModel() {
72 | let input = MarvelSearchViewModel.Input(searchText: searchText.asDriverComplete(),
73 | modelSelected: tableView.rx.modelSelected(MarvelHeroModel.self))
74 |
75 | let output = viewModel.transform(input: input)
76 | output.heros
77 | .do(onNext: { [weak self] (heros) in
78 | guard let self = self else {return}
79 | self.hideLoading()
80 | self.emptyLabel.isHidden = heros.count > 0 ? true:false
81 | })
82 | .bind(to: tableView.rx.items(cellIdentifier: MarvelSearchTVCell.reuseIdentifier, cellType: MarvelSearchTVCell.self)) { (row, hero, cell) in
83 | cell.configure(viewModel: .init(model: hero))
84 | }.disposed(by: disposeBag)
85 | }
86 |
87 | private func setProperties() {
88 | tableView.rx.setDelegate(self).disposed(by: disposeBag)
89 | tableView.backgroundColor = .clear
90 | tableView.separatorStyle = .none
91 | tableView.register(MarvelSearchTVCell.self, forCellReuseIdentifier: MarvelSearchTVCell.reuseIdentifier)
92 | }
93 |
94 | private func setupUI() {
95 | view.addSubview(tableView)
96 | view.addSubview(emptyLabel)
97 | view.addSubview(searchTextField)
98 | layout()
99 | }
100 |
101 | }
102 |
103 | // MARK: - Layout
104 |
105 | extension MarvelSearchVC {
106 |
107 | private func layout() {
108 | searchTextField.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 10).isActive = true
109 | searchTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
110 | searchTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
111 | searchTextField.heightAnchor.constraint(equalToConstant: 60).isActive = true
112 |
113 | tableView.topAnchor.constraint(equalTo: searchTextField.bottomAnchor, constant: 14).isActive = true
114 | tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 14).isActive = true
115 | tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -14).isActive = true
116 | tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
117 |
118 | emptyLabel.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
119 | emptyLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
120 | emptyLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
121 | emptyLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
122 | }
123 | }
124 |
125 | // MARK: - UITableViewDelegate
126 |
127 | extension MarvelSearchVC: UITableViewDelegate {
128 |
129 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
130 | return 320
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/RxSwiftMVVM/ViewController/MarvelDescriptionVC.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MarvelDescriptionVC.swift
3 | // RxSwiftMVVM
4 | //
5 | // Created by soom on 21/12/2018.
6 | //
7 |
8 | import RxCocoa
9 | import RxSwift
10 | import Kingfisher
11 |
12 | final class MarvelDescriptionVC: ViewController {
13 |
14 | // MARK: - NSLayoutConstraints
15 |
16 | private var containerViewTop: NSLayoutConstraint!
17 |
18 | // MARK: - Properties
19 |
20 | private let disposeBag = DisposeBag()
21 | private var viewModel: MarvelDescriptionViewModel!
22 |
23 | // MARK: - UI Components
24 |
25 | private let heroImageView = UIImageView().then {
26 | $0.translatesAutoresizingMaskIntoConstraints = false
27 | $0.contentMode = .scaleAspectFit
28 | }
29 | private let containerView = UIView().then {
30 | $0.translatesAutoresizingMaskIntoConstraints = false
31 | $0.backgroundColor = UIColor.white.withAlphaComponent(0.7)
32 | $0.clipsToBounds = true
33 | }
34 | private let descriptionButton = UIButton().then {
35 | $0.translatesAutoresizingMaskIntoConstraints = false
36 | $0.setTitle("DESCRIPTION", for: .normal)
37 | $0.setTitleColor(.black, for: .normal)
38 | $0.titleLabel?.font = .boldSystemFont(ofSize: 16)
39 | $0.backgroundColor = UIColor.white.withAlphaComponent(0.7)
40 | $0.isSelected = true
41 | }
42 | private let heroDescTextView = UITextView().then {
43 | $0.translatesAutoresizingMaskIntoConstraints = false
44 | $0.isEditable = false
45 | $0.backgroundColor = .clear
46 | $0.clipsToBounds = true
47 | }
48 |
49 | init(viewModel: MarvelDescriptionViewModel) {
50 | self.viewModel = viewModel
51 | super.init(nibName: nil, bundle: nil)
52 | showLoading()
53 | }
54 |
55 | required init?(coder aDecoder: NSCoder) {
56 | fatalError()
57 | }
58 |
59 | // MARK: - Overridden: ParentClass
60 |
61 | override func viewDidLoad() {
62 | super.viewDidLoad()
63 |
64 | bindView()
65 | bindViewModel()
66 | setupUI()
67 | }
68 |
69 | // MARK: - Private methods
70 |
71 | private func bindView() {
72 | descriptionButton.rx.tap
73 | .bind { [weak self] in
74 | guard let self = self else {return}
75 | let height = self.descriptionButton.isSelected ? 0:-(self.view.bounds.width-100)
76 |
77 | UIView.animate(withDuration: 0.3, animations: {
78 | self.containerViewTop.constant = height
79 | self.view.layoutIfNeeded()
80 | }) { (_) in
81 | self.descriptionButton.isSelected = !self.descriptionButton.isSelected
82 | }
83 | }
84 | .disposed(by: disposeBag)
85 | }
86 |
87 | private func bindViewModel() {
88 | let viewDidAppear = rx.sentMessage(#selector(UIViewController.viewDidAppear(_:))).take(1).mapToVoid().asDriverComplete()
89 | let input = MarvelDescriptionViewModel.Input(trigger: viewDidAppear)
90 |
91 | let output = viewModel.transform(input: input)
92 | output.thumbnail
93 | .drive(onNext: { [weak self] (url) in
94 | guard let self = self else {return}
95 | self.heroImageView.kf.setImage(with: url)
96 | self.hideLoading()
97 | })
98 | .disposed(by: disposeBag)
99 | output.name
100 | .drive(rx.title)
101 | .disposed(by: disposeBag)
102 | output.description
103 | .drive(heroDescTextView.rx.attributedText)
104 | .disposed(by: disposeBag)
105 | }
106 |
107 | private func setupUI() {
108 | view.addSubview(heroImageView)
109 | view.addSubview(containerView)
110 | view.addSubview(descriptionButton)
111 | containerView.addSubview(heroDescTextView)
112 | layout()
113 | }
114 |
115 | }
116 |
117 | // MARK: - Layout
118 |
119 | extension MarvelDescriptionVC {
120 |
121 | private func layout() {
122 | heroImageView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
123 | heroImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
124 | heroImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
125 | heroImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
126 |
127 | containerViewTop = containerView.topAnchor.constraint(equalTo: view.bottomAnchor, constant: -(view.bounds.width-100))
128 | containerViewTop.isActive = true
129 | containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
130 | containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
131 | containerView.heightAnchor.constraint(equalToConstant: view.bounds.width-100).isActive = true
132 |
133 | descriptionButton.bottomAnchor.constraint(equalTo: containerView.topAnchor, constant: 0).isActive = true
134 | descriptionButton.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
135 | descriptionButton.widthAnchor.constraint(equalToConstant: 130).isActive = true
136 | descriptionButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
137 |
138 | heroDescTextView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 8).isActive = true
139 | heroDescTextView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 8).isActive = true
140 | heroDescTextView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -8).isActive = true
141 | heroDescTextView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -8).isActive = true
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/RxSwiftMVVM.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3A4834CF21CC757F00D28416 /* Marvel_logo.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 3A4834CE21CC757F00D28416 /* Marvel_logo.jpg */; };
11 | 3A4834D121CC75A300D28416 /* MarvelService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834D021CC75A300D28416 /* MarvelService.swift */; };
12 | 3A4834D321CC75CC00D28416 /* MarvelHeroModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834D221CC75CC00D28416 /* MarvelHeroModel.swift */; };
13 | 3A4834D521CC761B00D28416 /* MarvelSearchTVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834D421CC761B00D28416 /* MarvelSearchTVCell.swift */; };
14 | 3A4834D721CC772400D28416 /* MarvelDescriptionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834D621CC772400D28416 /* MarvelDescriptionVC.swift */; };
15 | 3A4834D921CC774F00D28416 /* MarvelSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834D821CC774F00D28416 /* MarvelSearchVC.swift */; };
16 | 3A4834DB21CC776B00D28416 /* MarvelDescriptionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834DA21CC776B00D28416 /* MarvelDescriptionViewModel.swift */; };
17 | 3A4834DD21CC778700D28416 /* MarvelSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A4834DC21CC778700D28416 /* MarvelSearchViewModel.swift */; };
18 | 3AF9B59D21C1DDEF0096D1C3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B59C21C1DDEF0096D1C3 /* AppDelegate.swift */; };
19 | 3AF9B59F21C1DDEF0096D1C3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B59E21C1DDEF0096D1C3 /* ViewController.swift */; };
20 | 3AF9B5A221C1DDEF0096D1C3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3AF9B5A021C1DDEF0096D1C3 /* Main.storyboard */; };
21 | 3AF9B5A421C1DDF00096D1C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AF9B5A321C1DDF00096D1C3 /* Assets.xcassets */; };
22 | 3AF9B5A721C1DDF00096D1C3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3AF9B5A521C1DDF00096D1C3 /* LaunchScreen.storyboard */; };
23 | 3AF9B5B721C1E0C70096D1C3 /* AppDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5B621C1E0C70096D1C3 /* AppDefinition.swift */; };
24 | 9005716B9B42E868A65FF0AC /* Pods_RxSwiftMVVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EABD88FABAB27129E8DD339D /* Pods_RxSwiftMVVM.framework */; };
25 | ED8583442259C6F000CACD59 /* MarvelSearchTVCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8583432259C6F000CACD59 /* MarvelSearchTVCellViewModel.swift */; };
26 | ED8583472259DE9500CACD59 /* MarvelSearchNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8583462259DE9500CACD59 /* MarvelSearchNavigator.swift */; };
27 | ED858349225A384500CACD59 /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED858348225A384500CACD59 /* NavigationController.swift */; };
28 | ED85834C225A3EF900CACD59 /* ObservableType-Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED85834B225A3EF900CACD59 /* ObservableType-Extension.swift */; };
29 | /* End PBXBuildFile section */
30 |
31 | /* Begin PBXFileReference section */
32 | 3A4834CE21CC757F00D28416 /* Marvel_logo.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Marvel_logo.jpg; sourceTree = ""; };
33 | 3A4834D021CC75A300D28416 /* MarvelService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelService.swift; sourceTree = ""; };
34 | 3A4834D221CC75CC00D28416 /* MarvelHeroModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelHeroModel.swift; sourceTree = ""; };
35 | 3A4834D421CC761B00D28416 /* MarvelSearchTVCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelSearchTVCell.swift; sourceTree = ""; };
36 | 3A4834D621CC772400D28416 /* MarvelDescriptionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelDescriptionVC.swift; sourceTree = ""; };
37 | 3A4834D821CC774F00D28416 /* MarvelSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelSearchVC.swift; sourceTree = ""; };
38 | 3A4834DA21CC776B00D28416 /* MarvelDescriptionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelDescriptionViewModel.swift; sourceTree = ""; };
39 | 3A4834DC21CC778700D28416 /* MarvelSearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelSearchViewModel.swift; sourceTree = ""; };
40 | 3AF9B59921C1DDEF0096D1C3 /* RxSwiftMVVM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RxSwiftMVVM.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 3AF9B59C21C1DDEF0096D1C3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
42 | 3AF9B59E21C1DDEF0096D1C3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
43 | 3AF9B5A121C1DDEF0096D1C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
44 | 3AF9B5A321C1DDF00096D1C3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
45 | 3AF9B5A621C1DDF00096D1C3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
46 | 3AF9B5A821C1DDF00096D1C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
47 | 3AF9B5B621C1E0C70096D1C3 /* AppDefinition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDefinition.swift; sourceTree = ""; };
48 | 67571DE271057B2FA35AE281 /* Pods-RxSwiftMVVM.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVM.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM.release.xcconfig"; sourceTree = ""; };
49 | 6D930388EAA07CACC8BBAF61 /* Pods-RxSwiftMVVM.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxSwiftMVVM.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM.debug.xcconfig"; sourceTree = ""; };
50 | EABD88FABAB27129E8DD339D /* Pods_RxSwiftMVVM.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RxSwiftMVVM.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51 | ED8583432259C6F000CACD59 /* MarvelSearchTVCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelSearchTVCellViewModel.swift; sourceTree = ""; };
52 | ED8583462259DE9500CACD59 /* MarvelSearchNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarvelSearchNavigator.swift; sourceTree = ""; };
53 | ED858348225A384500CACD59 /* NavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = ""; };
54 | ED85834B225A3EF900CACD59 /* ObservableType-Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObservableType-Extension.swift"; sourceTree = ""; };
55 | /* End PBXFileReference section */
56 |
57 | /* Begin PBXFrameworksBuildPhase section */
58 | 3AF9B59621C1DDEF0096D1C3 /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 9005716B9B42E868A65FF0AC /* Pods_RxSwiftMVVM.framework in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 08F57457C4198AD88556BBBC /* Pods */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 6D930388EAA07CACC8BBAF61 /* Pods-RxSwiftMVVM.debug.xcconfig */,
73 | 67571DE271057B2FA35AE281 /* Pods-RxSwiftMVVM.release.xcconfig */,
74 | );
75 | name = Pods;
76 | sourceTree = "";
77 | };
78 | 3A4834CD21CC750800D28416 /* Resource */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 3A4834CE21CC757F00D28416 /* Marvel_logo.jpg */,
82 | );
83 | path = Resource;
84 | sourceTree = "";
85 | };
86 | 3AF9B59021C1DDEF0096D1C3 = {
87 | isa = PBXGroup;
88 | children = (
89 | 3AF9B59B21C1DDEF0096D1C3 /* RxSwiftMVVM */,
90 | 3AF9B59A21C1DDEF0096D1C3 /* Products */,
91 | 08F57457C4198AD88556BBBC /* Pods */,
92 | 916E1CE61F54C2E98E75B742 /* Frameworks */,
93 | );
94 | sourceTree = "";
95 | };
96 | 3AF9B59A21C1DDEF0096D1C3 /* Products */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 3AF9B59921C1DDEF0096D1C3 /* RxSwiftMVVM.app */,
100 | );
101 | name = Products;
102 | sourceTree = "";
103 | };
104 | 3AF9B59B21C1DDEF0096D1C3 /* RxSwiftMVVM */ = {
105 | isa = PBXGroup;
106 | children = (
107 | 3AF9B5A821C1DDF00096D1C3 /* Info.plist */,
108 | 3AF9B59C21C1DDEF0096D1C3 /* AppDelegate.swift */,
109 | ED858348225A384500CACD59 /* NavigationController.swift */,
110 | 3AF9B59E21C1DDEF0096D1C3 /* ViewController.swift */,
111 | 3AF9B5A321C1DDF00096D1C3 /* Assets.xcassets */,
112 | 3AF9B5B321C1DF220096D1C3 /* Const */,
113 | ED85834A225A3ED800CACD59 /* Extension */,
114 | 3AF9B5A521C1DDF00096D1C3 /* LaunchScreen.storyboard */,
115 | 3AF9B5A021C1DDEF0096D1C3 /* Main.storyboard */,
116 | 3AF9B5B121C1DF0A0096D1C3 /* Model */,
117 | ED8583452259DE5F00CACD59 /* Navigator */,
118 | 3A4834CD21CC750800D28416 /* Resource */,
119 | 3AF9B5B221C1DF150096D1C3 /* Service */,
120 | 3AF9B5B021C1DF050096D1C3 /* View */,
121 | 3AF9B5AE21C1DEF40096D1C3 /* ViewController */,
122 | 3AF9B5AF21C1DEFD0096D1C3 /* ViewModel */,
123 | );
124 | path = RxSwiftMVVM;
125 | sourceTree = "";
126 | };
127 | 3AF9B5AE21C1DEF40096D1C3 /* ViewController */ = {
128 | isa = PBXGroup;
129 | children = (
130 | 3A4834D621CC772400D28416 /* MarvelDescriptionVC.swift */,
131 | 3A4834D821CC774F00D28416 /* MarvelSearchVC.swift */,
132 | );
133 | path = ViewController;
134 | sourceTree = "";
135 | };
136 | 3AF9B5AF21C1DEFD0096D1C3 /* ViewModel */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 3A4834DA21CC776B00D28416 /* MarvelDescriptionViewModel.swift */,
140 | 3A4834DC21CC778700D28416 /* MarvelSearchViewModel.swift */,
141 | ED8583432259C6F000CACD59 /* MarvelSearchTVCellViewModel.swift */,
142 | );
143 | path = ViewModel;
144 | sourceTree = "";
145 | };
146 | 3AF9B5B021C1DF050096D1C3 /* View */ = {
147 | isa = PBXGroup;
148 | children = (
149 | 3A4834D421CC761B00D28416 /* MarvelSearchTVCell.swift */,
150 | );
151 | path = View;
152 | sourceTree = "";
153 | };
154 | 3AF9B5B121C1DF0A0096D1C3 /* Model */ = {
155 | isa = PBXGroup;
156 | children = (
157 | 3A4834D221CC75CC00D28416 /* MarvelHeroModel.swift */,
158 | );
159 | path = Model;
160 | sourceTree = "";
161 | };
162 | 3AF9B5B221C1DF150096D1C3 /* Service */ = {
163 | isa = PBXGroup;
164 | children = (
165 | 3A4834D021CC75A300D28416 /* MarvelService.swift */,
166 | );
167 | path = Service;
168 | sourceTree = "";
169 | };
170 | 3AF9B5B321C1DF220096D1C3 /* Const */ = {
171 | isa = PBXGroup;
172 | children = (
173 | 3AF9B5B621C1E0C70096D1C3 /* AppDefinition.swift */,
174 | );
175 | path = Const;
176 | sourceTree = "";
177 | };
178 | 916E1CE61F54C2E98E75B742 /* Frameworks */ = {
179 | isa = PBXGroup;
180 | children = (
181 | EABD88FABAB27129E8DD339D /* Pods_RxSwiftMVVM.framework */,
182 | );
183 | name = Frameworks;
184 | sourceTree = "";
185 | };
186 | ED8583452259DE5F00CACD59 /* Navigator */ = {
187 | isa = PBXGroup;
188 | children = (
189 | ED8583462259DE9500CACD59 /* MarvelSearchNavigator.swift */,
190 | );
191 | path = Navigator;
192 | sourceTree = "";
193 | };
194 | ED85834A225A3ED800CACD59 /* Extension */ = {
195 | isa = PBXGroup;
196 | children = (
197 | ED85834B225A3EF900CACD59 /* ObservableType-Extension.swift */,
198 | );
199 | path = Extension;
200 | sourceTree = "";
201 | };
202 | /* End PBXGroup section */
203 |
204 | /* Begin PBXNativeTarget section */
205 | 3AF9B59821C1DDEF0096D1C3 /* RxSwiftMVVM */ = {
206 | isa = PBXNativeTarget;
207 | buildConfigurationList = 3AF9B5AB21C1DDF00096D1C3 /* Build configuration list for PBXNativeTarget "RxSwiftMVVM" */;
208 | buildPhases = (
209 | A787573E3CFE222944E0F04D /* [CP] Check Pods Manifest.lock */,
210 | 3AF9B59521C1DDEF0096D1C3 /* Sources */,
211 | 3AF9B59621C1DDEF0096D1C3 /* Frameworks */,
212 | 3AF9B59721C1DDEF0096D1C3 /* Resources */,
213 | 49C3794F2E75DB18311E7CC7 /* [CP] Embed Pods Frameworks */,
214 | );
215 | buildRules = (
216 | );
217 | dependencies = (
218 | );
219 | name = RxSwiftMVVM;
220 | productName = RxSwiftMVVM;
221 | productReference = 3AF9B59921C1DDEF0096D1C3 /* RxSwiftMVVM.app */;
222 | productType = "com.apple.product-type.application";
223 | };
224 | /* End PBXNativeTarget section */
225 |
226 | /* Begin PBXProject section */
227 | 3AF9B59121C1DDEF0096D1C3 /* Project object */ = {
228 | isa = PBXProject;
229 | attributes = {
230 | LastSwiftUpdateCheck = 1010;
231 | LastUpgradeCheck = 1010;
232 | ORGANIZATIONNAME = cashwalk;
233 | TargetAttributes = {
234 | 3AF9B59821C1DDEF0096D1C3 = {
235 | CreatedOnToolsVersion = 10.1;
236 | };
237 | };
238 | };
239 | buildConfigurationList = 3AF9B59421C1DDEF0096D1C3 /* Build configuration list for PBXProject "RxSwiftMVVM" */;
240 | compatibilityVersion = "Xcode 9.3";
241 | developmentRegion = en;
242 | hasScannedForEncodings = 0;
243 | knownRegions = (
244 | en,
245 | Base,
246 | );
247 | mainGroup = 3AF9B59021C1DDEF0096D1C3;
248 | productRefGroup = 3AF9B59A21C1DDEF0096D1C3 /* Products */;
249 | projectDirPath = "";
250 | projectRoot = "";
251 | targets = (
252 | 3AF9B59821C1DDEF0096D1C3 /* RxSwiftMVVM */,
253 | );
254 | };
255 | /* End PBXProject section */
256 |
257 | /* Begin PBXResourcesBuildPhase section */
258 | 3AF9B59721C1DDEF0096D1C3 /* Resources */ = {
259 | isa = PBXResourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | 3AF9B5A721C1DDF00096D1C3 /* LaunchScreen.storyboard in Resources */,
263 | 3A4834CF21CC757F00D28416 /* Marvel_logo.jpg in Resources */,
264 | 3AF9B5A421C1DDF00096D1C3 /* Assets.xcassets in Resources */,
265 | 3AF9B5A221C1DDEF0096D1C3 /* Main.storyboard in Resources */,
266 | );
267 | runOnlyForDeploymentPostprocessing = 0;
268 | };
269 | /* End PBXResourcesBuildPhase section */
270 |
271 | /* Begin PBXShellScriptBuildPhase section */
272 | 49C3794F2E75DB18311E7CC7 /* [CP] Embed Pods Frameworks */ = {
273 | isa = PBXShellScriptBuildPhase;
274 | buildActionMask = 2147483647;
275 | files = (
276 | );
277 | inputPaths = (
278 | "${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM-frameworks.sh",
279 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
280 | "${BUILT_PRODUCTS_DIR}/CryptoSwift/CryptoSwift.framework",
281 | "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework",
282 | "${BUILT_PRODUCTS_DIR}/Result/Result.framework",
283 | "${BUILT_PRODUCTS_DIR}/RxAtomic/RxAtomic.framework",
284 | "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
285 | "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
286 | "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
287 | "${BUILT_PRODUCTS_DIR}/Then/Then.framework",
288 | );
289 | name = "[CP] Embed Pods Frameworks";
290 | outputPaths = (
291 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
292 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CryptoSwift.framework",
293 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework",
294 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework",
295 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxAtomic.framework",
296 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",
297 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
298 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
299 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Then.framework",
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | shellPath = /bin/sh;
303 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxSwiftMVVM/Pods-RxSwiftMVVM-frameworks.sh\"\n";
304 | showEnvVarsInLog = 0;
305 | };
306 | A787573E3CFE222944E0F04D /* [CP] Check Pods Manifest.lock */ = {
307 | isa = PBXShellScriptBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | );
311 | inputPaths = (
312 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
313 | "${PODS_ROOT}/Manifest.lock",
314 | );
315 | name = "[CP] Check Pods Manifest.lock";
316 | outputPaths = (
317 | "$(DERIVED_FILE_DIR)/Pods-RxSwiftMVVM-checkManifestLockResult.txt",
318 | );
319 | runOnlyForDeploymentPostprocessing = 0;
320 | shellPath = /bin/sh;
321 | 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";
322 | showEnvVarsInLog = 0;
323 | };
324 | /* End PBXShellScriptBuildPhase section */
325 |
326 | /* Begin PBXSourcesBuildPhase section */
327 | 3AF9B59521C1DDEF0096D1C3 /* Sources */ = {
328 | isa = PBXSourcesBuildPhase;
329 | buildActionMask = 2147483647;
330 | files = (
331 | 3A4834DB21CC776B00D28416 /* MarvelDescriptionViewModel.swift in Sources */,
332 | ED8583442259C6F000CACD59 /* MarvelSearchTVCellViewModel.swift in Sources */,
333 | ED85834C225A3EF900CACD59 /* ObservableType-Extension.swift in Sources */,
334 | 3A4834D521CC761B00D28416 /* MarvelSearchTVCell.swift in Sources */,
335 | 3AF9B5B721C1E0C70096D1C3 /* AppDefinition.swift in Sources */,
336 | 3A4834DD21CC778700D28416 /* MarvelSearchViewModel.swift in Sources */,
337 | 3A4834D721CC772400D28416 /* MarvelDescriptionVC.swift in Sources */,
338 | ED8583472259DE9500CACD59 /* MarvelSearchNavigator.swift in Sources */,
339 | 3AF9B59F21C1DDEF0096D1C3 /* ViewController.swift in Sources */,
340 | ED858349225A384500CACD59 /* NavigationController.swift in Sources */,
341 | 3A4834D121CC75A300D28416 /* MarvelService.swift in Sources */,
342 | 3A4834D921CC774F00D28416 /* MarvelSearchVC.swift in Sources */,
343 | 3AF9B59D21C1DDEF0096D1C3 /* AppDelegate.swift in Sources */,
344 | 3A4834D321CC75CC00D28416 /* MarvelHeroModel.swift in Sources */,
345 | );
346 | runOnlyForDeploymentPostprocessing = 0;
347 | };
348 | /* End PBXSourcesBuildPhase section */
349 |
350 | /* Begin PBXVariantGroup section */
351 | 3AF9B5A021C1DDEF0096D1C3 /* Main.storyboard */ = {
352 | isa = PBXVariantGroup;
353 | children = (
354 | 3AF9B5A121C1DDEF0096D1C3 /* Base */,
355 | );
356 | name = Main.storyboard;
357 | sourceTree = "";
358 | };
359 | 3AF9B5A521C1DDF00096D1C3 /* LaunchScreen.storyboard */ = {
360 | isa = PBXVariantGroup;
361 | children = (
362 | 3AF9B5A621C1DDF00096D1C3 /* Base */,
363 | );
364 | name = LaunchScreen.storyboard;
365 | sourceTree = "";
366 | };
367 | /* End PBXVariantGroup section */
368 |
369 | /* Begin XCBuildConfiguration section */
370 | 3AF9B5A921C1DDF00096D1C3 /* Debug */ = {
371 | isa = XCBuildConfiguration;
372 | buildSettings = {
373 | ALWAYS_SEARCH_USER_PATHS = NO;
374 | CLANG_ANALYZER_NONNULL = YES;
375 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
376 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
377 | CLANG_CXX_LIBRARY = "libc++";
378 | CLANG_ENABLE_MODULES = YES;
379 | CLANG_ENABLE_OBJC_ARC = YES;
380 | CLANG_ENABLE_OBJC_WEAK = YES;
381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
382 | CLANG_WARN_BOOL_CONVERSION = YES;
383 | CLANG_WARN_COMMA = YES;
384 | CLANG_WARN_CONSTANT_CONVERSION = YES;
385 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
386 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
387 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
388 | CLANG_WARN_EMPTY_BODY = YES;
389 | CLANG_WARN_ENUM_CONVERSION = YES;
390 | CLANG_WARN_INFINITE_RECURSION = YES;
391 | CLANG_WARN_INT_CONVERSION = YES;
392 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
393 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
394 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
396 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
397 | CLANG_WARN_STRICT_PROTOTYPES = YES;
398 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
399 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
400 | CLANG_WARN_UNREACHABLE_CODE = YES;
401 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
402 | CODE_SIGN_IDENTITY = "iPhone Developer";
403 | COPY_PHASE_STRIP = NO;
404 | DEBUG_INFORMATION_FORMAT = dwarf;
405 | ENABLE_STRICT_OBJC_MSGSEND = YES;
406 | ENABLE_TESTABILITY = YES;
407 | GCC_C_LANGUAGE_STANDARD = gnu11;
408 | GCC_DYNAMIC_NO_PIC = NO;
409 | GCC_NO_COMMON_BLOCKS = YES;
410 | GCC_OPTIMIZATION_LEVEL = 0;
411 | GCC_PREPROCESSOR_DEFINITIONS = (
412 | "DEBUG=1",
413 | "$(inherited)",
414 | );
415 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
416 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
417 | GCC_WARN_UNDECLARED_SELECTOR = YES;
418 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
419 | GCC_WARN_UNUSED_FUNCTION = YES;
420 | GCC_WARN_UNUSED_VARIABLE = YES;
421 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
422 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
423 | MTL_FAST_MATH = YES;
424 | ONLY_ACTIVE_ARCH = YES;
425 | SDKROOT = iphoneos;
426 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
427 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
428 | };
429 | name = Debug;
430 | };
431 | 3AF9B5AA21C1DDF00096D1C3 /* Release */ = {
432 | isa = XCBuildConfiguration;
433 | buildSettings = {
434 | ALWAYS_SEARCH_USER_PATHS = NO;
435 | CLANG_ANALYZER_NONNULL = YES;
436 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
437 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
438 | CLANG_CXX_LIBRARY = "libc++";
439 | CLANG_ENABLE_MODULES = YES;
440 | CLANG_ENABLE_OBJC_ARC = YES;
441 | CLANG_ENABLE_OBJC_WEAK = YES;
442 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
443 | CLANG_WARN_BOOL_CONVERSION = YES;
444 | CLANG_WARN_COMMA = YES;
445 | CLANG_WARN_CONSTANT_CONVERSION = YES;
446 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
447 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
448 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
449 | CLANG_WARN_EMPTY_BODY = YES;
450 | CLANG_WARN_ENUM_CONVERSION = YES;
451 | CLANG_WARN_INFINITE_RECURSION = YES;
452 | CLANG_WARN_INT_CONVERSION = YES;
453 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
454 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
455 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
456 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
457 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
458 | CLANG_WARN_STRICT_PROTOTYPES = YES;
459 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
460 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
461 | CLANG_WARN_UNREACHABLE_CODE = YES;
462 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
463 | CODE_SIGN_IDENTITY = "iPhone Developer";
464 | COPY_PHASE_STRIP = NO;
465 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
466 | ENABLE_NS_ASSERTIONS = NO;
467 | ENABLE_STRICT_OBJC_MSGSEND = YES;
468 | GCC_C_LANGUAGE_STANDARD = gnu11;
469 | GCC_NO_COMMON_BLOCKS = YES;
470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
472 | GCC_WARN_UNDECLARED_SELECTOR = YES;
473 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
474 | GCC_WARN_UNUSED_FUNCTION = YES;
475 | GCC_WARN_UNUSED_VARIABLE = YES;
476 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
477 | MTL_ENABLE_DEBUG_INFO = NO;
478 | MTL_FAST_MATH = YES;
479 | SDKROOT = iphoneos;
480 | SWIFT_COMPILATION_MODE = wholemodule;
481 | SWIFT_OPTIMIZATION_LEVEL = "-O";
482 | VALIDATE_PRODUCT = YES;
483 | };
484 | name = Release;
485 | };
486 | 3AF9B5AC21C1DDF00096D1C3 /* Debug */ = {
487 | isa = XCBuildConfiguration;
488 | baseConfigurationReference = 6D930388EAA07CACC8BBAF61 /* Pods-RxSwiftMVVM.debug.xcconfig */;
489 | buildSettings = {
490 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
491 | CODE_SIGN_STYLE = Automatic;
492 | DEVELOPMENT_TEAM = "";
493 | INFOPLIST_FILE = RxSwiftMVVM/Info.plist;
494 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
495 | LD_RUNPATH_SEARCH_PATHS = (
496 | "$(inherited)",
497 | "@executable_path/Frameworks",
498 | );
499 | PRODUCT_BUNDLE_IDENTIFIER = io.cashawalk.RxSwiftMVVM;
500 | PRODUCT_NAME = "$(TARGET_NAME)";
501 | SWIFT_VERSION = 4.2;
502 | TARGETED_DEVICE_FAMILY = "1,2";
503 | };
504 | name = Debug;
505 | };
506 | 3AF9B5AD21C1DDF00096D1C3 /* Release */ = {
507 | isa = XCBuildConfiguration;
508 | baseConfigurationReference = 67571DE271057B2FA35AE281 /* Pods-RxSwiftMVVM.release.xcconfig */;
509 | buildSettings = {
510 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
511 | CODE_SIGN_STYLE = Automatic;
512 | DEVELOPMENT_TEAM = "";
513 | INFOPLIST_FILE = RxSwiftMVVM/Info.plist;
514 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
515 | LD_RUNPATH_SEARCH_PATHS = (
516 | "$(inherited)",
517 | "@executable_path/Frameworks",
518 | );
519 | PRODUCT_BUNDLE_IDENTIFIER = io.cashawalk.RxSwiftMVVM;
520 | PRODUCT_NAME = "$(TARGET_NAME)";
521 | SWIFT_VERSION = 4.2;
522 | TARGETED_DEVICE_FAMILY = "1,2";
523 | };
524 | name = Release;
525 | };
526 | /* End XCBuildConfiguration section */
527 |
528 | /* Begin XCConfigurationList section */
529 | 3AF9B59421C1DDEF0096D1C3 /* Build configuration list for PBXProject "RxSwiftMVVM" */ = {
530 | isa = XCConfigurationList;
531 | buildConfigurations = (
532 | 3AF9B5A921C1DDF00096D1C3 /* Debug */,
533 | 3AF9B5AA21C1DDF00096D1C3 /* Release */,
534 | );
535 | defaultConfigurationIsVisible = 0;
536 | defaultConfigurationName = Release;
537 | };
538 | 3AF9B5AB21C1DDF00096D1C3 /* Build configuration list for PBXNativeTarget "RxSwiftMVVM" */ = {
539 | isa = XCConfigurationList;
540 | buildConfigurations = (
541 | 3AF9B5AC21C1DDF00096D1C3 /* Debug */,
542 | 3AF9B5AD21C1DDF00096D1C3 /* Release */,
543 | );
544 | defaultConfigurationIsVisible = 0;
545 | defaultConfigurationName = Release;
546 | };
547 | /* End XCConfigurationList section */
548 | };
549 | rootObject = 3AF9B59121C1DDEF0096D1C3 /* Project object */;
550 | }
551 |
--------------------------------------------------------------------------------