├── .gitignore ├── ArticleImages ├── initial_sketch.png ├── unidirectional_data_flow.png └── use_case_sketch.png ├── LICENSE ├── README-PT.md ├── README.md └── ReduxPaperScissors ├── Podfile ├── Podfile.lock ├── Pods ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── ReSwift │ ├── LICENSE.md │ ├── README.md │ └── ReSwift │ │ ├── CoreTypes │ │ ├── Action.swift │ │ ├── DispatchingStoreType.swift │ │ ├── Middleware.swift │ │ ├── Reducer.swift │ │ ├── State.swift │ │ ├── Store.swift │ │ ├── StoreSubscriber.swift │ │ ├── StoreType.swift │ │ └── Subscription.swift │ │ └── Utils │ │ ├── Assertions.swift │ │ ├── Coding.swift │ │ └── TypeHelper.swift └── Target Support Files │ ├── Pods-ReduxPaperScissors │ ├── Info.plist │ ├── Pods-ReduxPaperScissors-acknowledgements.markdown │ ├── Pods-ReduxPaperScissors-acknowledgements.plist │ ├── Pods-ReduxPaperScissors-dummy.m │ ├── Pods-ReduxPaperScissors-frameworks.sh │ ├── Pods-ReduxPaperScissors-resources.sh │ ├── Pods-ReduxPaperScissors-umbrella.h │ ├── Pods-ReduxPaperScissors.debug.xcconfig │ ├── Pods-ReduxPaperScissors.modulemap │ └── Pods-ReduxPaperScissors.release.xcconfig │ ├── Pods-ReduxPaperScissorsTests │ ├── Info.plist │ ├── Pods-ReduxPaperScissorsTests-acknowledgements.markdown │ ├── Pods-ReduxPaperScissorsTests-acknowledgements.plist │ ├── Pods-ReduxPaperScissorsTests-dummy.m │ ├── Pods-ReduxPaperScissorsTests-frameworks.sh │ ├── Pods-ReduxPaperScissorsTests-resources.sh │ ├── Pods-ReduxPaperScissorsTests-umbrella.h │ ├── Pods-ReduxPaperScissorsTests.debug.xcconfig │ ├── Pods-ReduxPaperScissorsTests.modulemap │ └── Pods-ReduxPaperScissorsTests.release.xcconfig │ └── ReSwift │ ├── Info.plist │ ├── ReSwift-dummy.m │ ├── ReSwift-prefix.pch │ ├── ReSwift-umbrella.h │ ├── ReSwift.modulemap │ └── ReSwift.xcconfig ├── ReduxPaperScissors.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── ReduxPaperScissors.xcworkspace └── contents.xcworkspacedata ├── ReduxPaperScissors ├── Actions.swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Reducers.swift ├── State.swift └── ViewController.swift └── ReduxPaperScissorsTests ├── Info.plist └── ReduxPaperScissorsTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /ArticleImages/initial_sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliobertolacini/ReduxPaperSwift/d3849a7b71043c41cba39c51d5de667347b5afca/ArticleImages/initial_sketch.png -------------------------------------------------------------------------------- /ArticleImages/unidirectional_data_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliobertolacini/ReduxPaperSwift/d3849a7b71043c41cba39c51d5de667347b5afca/ArticleImages/unidirectional_data_flow.png -------------------------------------------------------------------------------- /ArticleImages/use_case_sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juliobertolacini/ReduxPaperSwift/d3849a7b71043c41cba39c51d5de667347b5afca/ArticleImages/use_case_sketch.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Julio Bertolacini 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 | -------------------------------------------------------------------------------- /README-PT.md: -------------------------------------------------------------------------------- 1 | # ReduxPaperSwift 2 | Uma simples abordagem para aprender os primórdios de Redux em Swift. 3 | 4 | [[Click here to change the language of this article to English.](README.md)] 5 | 6 | ## Introdução 7 | Redux é a implementação de um padrão arquitetural de software que prioriza o fluxo de dados unidirecional. 8 | Foi criada a partir da arquitetura Flux (desenvolvida pelo Facebook), vem crescendo bastante no desenvolvimento de aplicações e promete grandes vantagens na sua utilização. 9 | Ela é uma alternativa a outros padrões arquiteturais como, por exemplo: MVC, MVVM, Viper e CleanSwift. 10 | 11 | ## Vantagens 12 | Uma das grandes promessas do Redux é criar restrições que incentivam um desenvolvimento de software mais organizado e mais fácil de testar, assim, por esses motivos, acaba diminuindo a complexidade na fase de desenvolvimento além de oferecer facilidades na manutenção do estado da aplicação e depuração avançada. 13 | 14 | Este artigo descreve uma abordagem simples para começar a entender este novo padrão. 15 | 16 | ## Requisitos para a implementação 17 | - Nível básico na construção de aplicações em iOS (Swift + Xcode). 18 | - Conhecimento do padrão de projeto Observer. 19 | - Saber utilizar o sistema de dependências CocoaPods. 20 | 21 | ## Componentes 22 | 23 | - **State:** Representa o estado da aplicação. Deve existir apenas um, podendo este ser dividido em sub-estados. 24 | - **Actions:** São objetos simples que descrevem o que o sistema pode fazer. Esses objetos podem carregar informações ou não, dependendo do caso. Eles são despachados pela camada View como intenções de alterar o estado da aplicação. 25 | - **Reducers:** É aqui que desenvolvemos a lógica principal da aplicação. Reducers devem ser funções puras, sem efeitos colaterais e devem ser síncronos. São os únicos objetos que podem criar um novo estado para a aplicação. Eles recebem uma ação e o estado atual, e retornam um novo estado. 26 | 27 | ![imagem do fluxo](/ArticleImages/unidirectional_data_flow.png) 28 | 29 | Vejam que o fluxo unidirecional acontece quando a View despacha uma Action. Essa Action é passada para o Reducer correspondente, então este Reducer gera um novo State de acordo com a Action passada, e o State é passado de volta para a View para que esta seja alterada. 30 | 31 | - **Store:** É um dos componentes mais importantes dessa implementação. É ela que agrega todos os componentes citados acima e faz o fluxo funcionar. A View despacha uma nova Action para a Store. A Store então, passa essa Action para o Reducer junto com o State atual e então recebe de volta o novo State do Reducer. A View é avisada sempre que um novo State é criado, isso é possível pela implementação do padrão de projeto **Observer** que permite que a View se torne "assinante" da Store, para ser notificada. 32 | 33 | ## Vamos começar 34 | Minha abordagem para começarmos a aprender Redux é construir uma aplicação de exemplo - um jogo de "Pedra, Papel e Tesoura" - utilizando uma biblioteca chamada ReSwift que implementa os conceitos dessa arquitetura em Swift. 35 | 36 | Começamos então fazendo um esboço de como deve ser a aplicação. Para simplificar, a aplicação deverá funcionar em um único ViewController, contendo 3 botões na parte inferior (Pedra, Papel e Tesoura), 1 campo de mensagem na parte superior e 2 placeholders para mostrar quando um jogador já realizou sua jogada e no final para revelar a arma dos jogadores. 37 | 38 | ![imagem da view](/ArticleImages/initial_sketch.png) 39 | 40 | Para começar o desenvolvimento propus um caso de uso em que o Jogador1 escolhe **Tesousa** e o Jogador2 escolhe **Pedra**, resultando na vitória do Jogador2. Esse fluxo aconteceria da seguinte forma: 41 | 42 | ![imagem da view](/ArticleImages/use_case_sketch.png) 43 | 44 | ## Desenvolvimento 45 | 46 | Criamos um novo projeto no Xcode do tipo "Single view application" e habilitamos "Include Unit Tests" para podermos fazer um teste usando os conceitos de Redux. 47 | 48 | Instale o pod ["ReSwift"](https://github.com/ReSwift/ReSwift), utilizando [CocoaPods](https://cocoapods.org/). 49 | 50 | Em seguida vamos criar o primeiro componente, o **State**. Observando as imagens acima, conseguimos perceber claramente as partes do app que irão se alterar durante a execução, cada parte desta consiste no estado da aplicação. Criei então um arquivo `State.swift` e dentro dele coloquei as estruturas que formam o estado, juntamente com possíveis estruturas de modelo que formam o conceito da aplicação. É importante salientar que as estruturas devem ser imutáveis para que o Redux funcione, só assim garantimos que o State seja alterado apenas pelos Reducers, por isso utilizei Structs e Enums ao invés de Classes: 51 | 52 | ``` swift 53 | import ReSwift 54 | 55 | // MARK:- STATE 56 | 57 | struct AppState: StateType { 58 | 59 | var message: Message 60 | var turn: Turn 61 | var player1Play: Play 62 | var player2Play: Play 63 | var result: Result? 64 | 65 | init() { 66 | 67 | self.message = .player1choose 68 | self.turn = Turn(player: .one) 69 | self.player1Play = Play(chosen: false, weapon: nil) 70 | self.player2Play = Play(chosen: false, weapon: nil) 71 | } 72 | } 73 | 74 | 75 | // MARK:- MODEL & OPTIONS 76 | 77 | enum Message: String { 78 | 79 | case player1choose = "PLAYER 1 - Choose your weapon:" 80 | case player2choose = "PLAYER 2 - Choose your weapon:" 81 | case player1wins = "PLAYER 1 WINS!" 82 | case player2wins = "PLAYER 2 WINS!" 83 | case draw = "DRAW!" 84 | } 85 | 86 | struct Turn { 87 | 88 | var player: Player 89 | } 90 | 91 | enum Player { 92 | 93 | case one 94 | case two 95 | } 96 | 97 | struct Play { 98 | 99 | var chosen: Bool 100 | var weapon: Weapon? 101 | } 102 | 103 | enum Weapon: String { 104 | 105 | case rock = "Rock" 106 | case paper = "Paper" 107 | case scissors = "Scissors" 108 | } 109 | 110 | enum Result { 111 | 112 | case draw 113 | case player1wins 114 | case player2wins 115 | } 116 | ``` 117 | 118 | Agora vamos criar uma Action, que será a descrição de uma ação que tem intenção de alterar o State. Neste caso temos apenas uma, ChooseWeaponAction, que é disparada quando cada jogador escolhe uma arma: 119 | 120 | ``` swift 121 | import ReSwift 122 | 123 | // MARK:- ACTIONS 124 | 125 | struct ChooseWeaponAction: Action { 126 | 127 | var weapon: Weapon 128 | } 129 | ``` 130 | 131 | Por último vamos construir o Reducer, aqui nós filtramos a Action criada, pegamos o State atual da aplicação e geramos um novo State baseado na lógica que desenvolveremos com as informações contidas na Action: 132 | 133 | 134 | ``` swift 135 | import ReSwift 136 | 137 | // MARK:- REDUCERS 138 | 139 | func appReducer(action: Action, state: AppState?) -> AppState { 140 | 141 | // creates a new state if one does not already exist 142 | var state = state ?? AppState() 143 | 144 | switch action { 145 | case let chooseWeaponAction as ChooseWeaponAction: 146 | 147 | let turn = state.turn 148 | switch turn.player { 149 | case .one: 150 | 151 | // create a play 152 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 153 | state.player1Play = play 154 | 155 | // pass the turn to the next player 156 | state.turn = Turn(player: .two) 157 | 158 | // change the message 159 | state.message = .player2choose 160 | 161 | case .two: 162 | 163 | // create a play 164 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 165 | state.player2Play = play 166 | 167 | // calculate who won 168 | let player1weapon = state.player1Play.weapon ?? .rock 169 | let player2weapon = state.player2Play.weapon ?? .rock 170 | 171 | switch player1weapon { 172 | case .rock: 173 | switch player2weapon { 174 | case .rock: 175 | state.result = .draw 176 | state.message = .draw 177 | case .paper: 178 | state.result = .player2wins 179 | state.message = .player2wins 180 | case .scissors: 181 | state.result = .player1wins 182 | state.message = .player1wins 183 | } 184 | case .paper: 185 | switch player2weapon { 186 | case .rock: 187 | state.result = .player1wins 188 | state.message = .player1wins 189 | case .paper: 190 | state.result = .draw 191 | state.message = .draw 192 | case .scissors: 193 | state.result = .player2wins 194 | state.message = .player2wins 195 | } 196 | case .scissors: 197 | switch player2weapon { 198 | case .rock: 199 | state.result = .player2wins 200 | state.message = .player2wins 201 | case .paper: 202 | state.result = .player1wins 203 | state.message = .player1wins 204 | case .scissors: 205 | state.result = .draw 206 | state.message = .draw 207 | } 208 | } 209 | } 210 | 211 | default: 212 | break 213 | } 214 | 215 | // return the new state 216 | return state 217 | } 218 | ``` 219 | 220 | ## Teste 221 | 222 | Pronto, simples assim, nós implementamos um padrão Redux com fluxo unidirecional. Para mostrar a facilidade de testar esse tipo de arquitetura, construi esta classe de XCTest que testa lógicas da aplicação sem mesmo termos construído a UI (View). 223 | 224 | 225 | ``` swift 226 | import XCTest 227 | import ReSwift 228 | @testable import ReduxPaperSwift 229 | 230 | class ReduxPaperSwiftTests: XCTestCase { 231 | 232 | // testing whether a rule works. 233 | func test1() { 234 | 235 | let store = Store(reducer: appReducer, state: nil) 236 | 237 | // Player 1 choose 238 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 239 | 240 | // Player 2 choose 241 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 242 | 243 | // Check result 244 | XCTAssertEqual(store.state.result, .player1wins) 245 | } 246 | 247 | // testing whether another rule works. 248 | func test2() { 249 | 250 | let store = Store(reducer: appReducer, state: nil) 251 | 252 | // Player 1 choose 253 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 254 | 255 | // Player 2 choose 256 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 257 | 258 | // Check result 259 | XCTAssertEqual(store.state.result, .player2wins) 260 | } 261 | 262 | } 263 | ``` 264 | 265 | ## Finalizando 266 | 267 | Para finalizar, criei um ViewController com as características mostradas do desenho de esboço, e fiz esse ViewController se tornar um "assinante" da Store, podendo assim executar uma mudança nas views sempre que o State mudar. Isso acontece com a implementação do protocolo StoreSubscriber: 268 | 269 | ``` swift 270 | import UIKit 271 | import ReSwift 272 | 273 | class ViewController: UIViewController, StoreSubscriber { 274 | 275 | @IBOutlet weak var message: UILabel! 276 | @IBOutlet weak var placeholder1: UILabel! 277 | @IBOutlet weak var placeholder2: UILabel! 278 | 279 | @IBAction func rockButton(_ sender: Any) { 280 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 281 | } 282 | 283 | @IBAction func paperButton(_ sender: Any) { 284 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 285 | } 286 | 287 | @IBAction func scissorsButton(_ sender: Any) { 288 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 289 | } 290 | 291 | override func viewDidLoad() { 292 | super.viewDidLoad() 293 | 294 | store.subscribe(self) 295 | } 296 | 297 | func newState(state: AppState) { 298 | 299 | message.text = state.message.rawValue 300 | 301 | if state.player2Play.chosen { 302 | placeholder1.text = state.player1Play.weapon?.rawValue 303 | placeholder2.text = state.player2Play.weapon?.rawValue 304 | } else { 305 | placeholder1.text = state.player1Play.chosen ? "chosen" : "" 306 | } 307 | } 308 | } 309 | ``` 310 | 311 | ## Créditos 312 | - [Redux](http://redux.js.org/) 313 | - [ReSwift](https://github.com/ReSwift/ReSwift) 314 | 315 | 316 | ## Para se aprofundar no assunto 317 | - [Tutorial de ReSwift do site Ray Wenderlich](https://www.raywenderlich.com/155815/reswift-tutorial-memory-game-app) 318 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReduxPaperSwift 2 | 3 | A simple approach to learning the beginnings of Redux in Swift. 4 | 5 | [Click here to change the language of this article to Portuguese.](README-PT.md) 6 | 7 | ## Introduction 8 | 9 | Redux is the implementation of an architectural software pattern that prioritizes unidirectional data flow. 10 | Created from the Flux architecture (developed by Facebook), it has grown considerably in the development of applications and promises great advantages in its use. 11 | It is an alternative to other architectural patterns such as: MVC, MVVM and Viper. 12 | 13 | ## Benefits 14 | 15 | One of the great promises of Redux is to create constraints that encourage a more organized software development and easier to test, so for these reasons, ends up reducing the complexity in the development phase as well as offering facilities in maintaining the application state and advanced debugging. 16 | 17 | This article describes a simple approach to beginning to understand this new pattern. 18 | 19 | ## Requirements for implementation 20 | 21 | - Basic level in building applications on iOS (Swift + Xcode). 22 | - Knowledge of [Observer](https://en.wikipedia.org/wiki/Observer_pattern) pattern. 23 | - Know how to use the [CocoaPods](https://cocoapods.org/) dependency system. 24 | 25 | ## Components 26 | 27 | - **State:** Represents the state of the application. There must be only one, which can be divided into sub-states. 28 | - **Actions:** These are simple objects that describe what the system can do. These objects can carry information or not, depending on the case. They are dispatched by the View layer as intentions to change the state of the application. 29 | - **Reducers:** This is where we develop the main logic of the application. Reducers must be pure functions with no side effects and must be synchronous. They are the only objects that can create a new state for the application. They are given an action and the current state, and they return a new state. 30 | 31 | ![data_flow_image](/ArticleImages/unidirectional_data_flow.png) 32 | 33 | Notice that the unidirectional flow happens when the View dispatches an Action. This Action is passed to the corresponding Reducer, so this Reducer generates a new State according to the previous Action, and the State is passed back to the View so that it is changed. 34 | 35 | - **Store:** It is one of the most important components of this implementation. It is what aggregates all the components mentioned above and makes the flow work. View dispatches a new Action to the Store. The Store then passes this Action to Reducer along with the current State and then receives the Reducer's new State back. The View is warned whenever a new State is created, this is possible by implementing the **Observer** design pattern that allows View to become a "subscriber" of the Store to be notified. 36 | 37 | ## Let's start 38 | My approach to begin to learn Redux is to build a sample application - a "Rock, Paper and Scissors" game - using a library called ReSwift that implements the concepts of this architecture in Swift. 39 | 40 | We begin by sketching what the application should look like. For simplicity, the application should work on a single ViewController, containing 3 buttons at the bottom (Rock, Paper and Scissors), 1 message field at the top, and 2 placeholders to show when a player has already made his move and at the end to reveal the weapons of the players. 41 | 42 | ![initial_sketch](/ArticleImages/initial_sketch.png) 43 | 44 | To start the development I proposed a use case in which Player1 chooses **Scissors** and Player2 chooses **Rock**, resulting in Player2's victory. This flow would happen as follows: 45 | 46 | ![use_case_sketch](/ArticleImages/use_case_sketch.png) 47 | 48 | ## Development 49 | 50 | Create a new "Single view application" project in Xcode and enable "Include Unit Tests" to be able to make a test using the concepts of Redux. 51 | 52 | Install the ["ReSwift"](https://github.com/ReSwift/ReSwift) pod using [CocoaPods](https://cocoapods.org/). 53 | 54 | Next we will create the first component, the **State**. Looking at the images above, we can see clearly the parts of the app that will change during execution, each part of which consists of the state of the application. I then created a `State.swift` file and placed the state-forming structures inside it, along with possible template structures that form the concept of the application. It is important to point out that the structures must be immutable so that Redux works, only then we ensure that the State is changed exclusively by the Reducers, so I used Structs and Enums instead of Classes: 55 | 56 | ``` swift 57 | import ReSwift 58 | 59 | // MARK:- STATE 60 | 61 | struct AppState: StateType { 62 | 63 | var message: Message 64 | var turn: Turn 65 | var player1Play: Play 66 | var player2Play: Play 67 | var result: Result? 68 | 69 | init() { 70 | 71 | self.message = .player1choose 72 | self.turn = Turn(player: .one) 73 | self.player1Play = Play(chosen: false, weapon: nil) 74 | self.player2Play = Play(chosen: false, weapon: nil) 75 | } 76 | } 77 | 78 | 79 | // MARK:- MODEL & OPTIONS 80 | 81 | enum Message: String { 82 | 83 | case player1choose = "PLAYER 1 - Choose your weapon:" 84 | case player2choose = "PLAYER 2 - Choose your weapon:" 85 | case player1wins = "PLAYER 1 WINS!" 86 | case player2wins = "PLAYER 2 WINS!" 87 | case draw = "DRAW!" 88 | } 89 | 90 | struct Turn { 91 | 92 | var player: Player 93 | } 94 | 95 | enum Player { 96 | 97 | case one 98 | case two 99 | } 100 | 101 | struct Play { 102 | 103 | var chosen: Bool 104 | var weapon: Weapon? 105 | } 106 | 107 | enum Weapon: String { 108 | 109 | case rock = "Rock" 110 | case paper = "Paper" 111 | case scissors = "Scissors" 112 | } 113 | 114 | enum Result { 115 | 116 | case draw 117 | case player1wins 118 | case player2wins 119 | } 120 | ``` 121 | 122 | Now let's create an Action, which will be the description of an action that intends to change the State. In this case we have only one, ChooseWeaponAction, which is triggered when each player chooses a weapon: 123 | 124 | ``` swift 125 | import ReSwift 126 | 127 | // MARK:- ACTIONS 128 | 129 | struct ChooseWeaponAction: Action { 130 | 131 | var weapon: Weapon 132 | } 133 | ``` 134 | 135 | Finally we shall build the Reducer. Here we filter the Action created, we take the current state of the application and generate a new State based on the logic that we will develop with the information contained in Action: 136 | 137 | 138 | ``` swift 139 | import ReSwift 140 | 141 | // MARK:- REDUCERS 142 | 143 | func appReducer(action: Action, state: AppState?) -> AppState { 144 | 145 | // creates a new state if one does not already exist 146 | var state = state ?? AppState() 147 | 148 | switch action { 149 | case let chooseWeaponAction as ChooseWeaponAction: 150 | 151 | let turn = state.turn 152 | switch turn.player { 153 | case .one: 154 | 155 | // create a play 156 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 157 | state.player1Play = play 158 | 159 | // pass the turn to the next player 160 | state.turn = Turn(player: .two) 161 | 162 | // change the message 163 | state.message = .player2choose 164 | 165 | case .two: 166 | 167 | // create a play 168 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 169 | state.player2Play = play 170 | 171 | // calculate who won 172 | let player1weapon = state.player1Play.weapon ?? .rock 173 | let player2weapon = state.player2Play.weapon ?? .rock 174 | 175 | switch player1weapon { 176 | case .rock: 177 | switch player2weapon { 178 | case .rock: 179 | state.result = .draw 180 | state.message = .draw 181 | case .paper: 182 | state.result = .player2wins 183 | state.message = .player2wins 184 | case .scissors: 185 | state.result = .player1wins 186 | state.message = .player1wins 187 | } 188 | case .paper: 189 | switch player2weapon { 190 | case .rock: 191 | state.result = .player1wins 192 | state.message = .player1wins 193 | case .paper: 194 | state.result = .draw 195 | state.message = .draw 196 | case .scissors: 197 | state.result = .player2wins 198 | state.message = .player2wins 199 | } 200 | case .scissors: 201 | switch player2weapon { 202 | case .rock: 203 | state.result = .player2wins 204 | state.message = .player2wins 205 | case .paper: 206 | state.result = .player1wins 207 | state.message = .player1wins 208 | case .scissors: 209 | state.result = .draw 210 | state.message = .draw 211 | } 212 | } 213 | } 214 | 215 | default: 216 | break 217 | } 218 | 219 | // return the new state 220 | return state 221 | } 222 | ``` 223 | 224 | ## Test 225 | 226 | Done, simple like that, we've implemented a Redux pattern with unidirectional flow. To show the ease of testing this type of architecture, I built this XCTest class that tests application logic without even having built a UI Layer (View). 227 | 228 | 229 | ``` swift 230 | import XCTest 231 | import ReSwift 232 | @testable import ReduxPaperSwift 233 | 234 | class ReduxPaperSwiftTests: XCTestCase { 235 | 236 | // testing whether a rule works. 237 | func test1() { 238 | 239 | let store = Store(reducer: appReducer, state: nil) 240 | 241 | // Player 1 choose 242 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 243 | 244 | // Player 2 choose 245 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 246 | 247 | // Check result 248 | XCTAssertEqual(store.state.result, .player1wins) 249 | } 250 | 251 | // testing whether another rule works. 252 | func test2() { 253 | 254 | let store = Store(reducer: appReducer, state: nil) 255 | 256 | // Player 1 choose 257 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 258 | 259 | // Player 2 choose 260 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 261 | 262 | // Check result 263 | XCTAssertEqual(store.state.result, .player2wins) 264 | } 265 | 266 | } 267 | ``` 268 | 269 | ## Finishing 270 | 271 | Finally, I created a ViewController with the characteristics shown in the sketch drawing, and made this ViewController become a "subscriber" of the Store, so I can perform a change in the views whenever the State changes. This happens with the implementation of the StoreSubscriber protocol: 272 | 273 | ``` swift 274 | import UIKit 275 | import ReSwift 276 | 277 | class ViewController: UIViewController, StoreSubscriber { 278 | 279 | @IBOutlet weak var message: UILabel! 280 | @IBOutlet weak var placeholder1: UILabel! 281 | @IBOutlet weak var placeholder2: UILabel! 282 | 283 | @IBAction func rockButton(_ sender: Any) { 284 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 285 | } 286 | 287 | @IBAction func paperButton(_ sender: Any) { 288 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 289 | } 290 | 291 | @IBAction func scissorsButton(_ sender: Any) { 292 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 293 | } 294 | 295 | override func viewDidLoad() { 296 | super.viewDidLoad() 297 | 298 | store.subscribe(self) 299 | } 300 | 301 | func newState(state: AppState) { 302 | 303 | message.text = state.message.rawValue 304 | 305 | if state.player2Play.chosen { 306 | placeholder1.text = state.player1Play.weapon?.rawValue 307 | placeholder2.text = state.player2Play.weapon?.rawValue 308 | } else { 309 | placeholder1.text = state.player1Play.chosen ? "chosen" : "" 310 | } 311 | } 312 | } 313 | ``` 314 | 315 | ## Credits 316 | 317 | - [Redux](http://redux.js.org/) 318 | - [ReSwift](https://github.com/ReSwift/ReSwift) 319 | 320 | 321 | ## To dig deeper into the subject: 322 | 323 | - [Ray Wenderlich's ReSwift Tutorial](https://www.raywenderlich.com/155815/reswift-tutorial-memory-game-app) 324 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'ReduxPaperScissors' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for ReduxPaperScissors 9 | pod "ReSwift" 10 | 11 | target 'ReduxPaperScissorsTests' do 12 | inherit! :search_paths 13 | # Pods for testing 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ReSwift (4.0.0) 3 | 4 | DEPENDENCIES: 5 | - ReSwift 6 | 7 | SPEC CHECKSUMS: 8 | ReSwift: f058ef13b46ae5f463f10605ccbbb7fb04424d8d 9 | 10 | PODFILE CHECKSUM: 1fc2c75bf31083136950e188fcd5871abc982cc3 11 | 12 | COCOAPODS: 1.2.0 13 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - ReSwift (4.0.0) 3 | 4 | DEPENDENCIES: 5 | - ReSwift 6 | 7 | SPEC CHECKSUMS: 8 | ReSwift: f058ef13b46ae5f463f10605ccbbb7fb04424d8d 9 | 10 | PODFILE CHECKSUM: 1fc2c75bf31083136950e188fcd5871abc982cc3 11 | 12 | COCOAPODS: 1.2.0 13 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Pods.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1639EB1ED7BCE62D9D8FECB54A95F904 /* Middleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC871B7066428FF774C5F9208197F11C /* Middleware.swift */; }; 11 | 1EA192E2FCD1B24CBF697C8D4A707CF4 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2711A63FBF227A0CA669ED1D1EDB8F56 /* Action.swift */; }; 12 | 2391BD100154145FE32BDAAA471D6E20 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 13 | 2D7712B9C887214EEC565B50B3D506CE /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 375E8868F8F6D6961F33EDED16FF1D5E /* State.swift */; }; 14 | 3114D0D9947B4B9FAA0A8041E2410252 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 15 | 44107B8D1D771E8620E2700D7E3D3843 /* ReSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5279BEEA93D3BB399FBCB375ADD3ACB4 /* ReSwift-dummy.m */; }; 16 | 48C00892E2C4B8EA57C3C91BA44F4E5E /* Assertions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F3C38E9357DF11B55A4279C68A73D47 /* Assertions.swift */; }; 17 | 608639A2B060F3A450E80F304766B83F /* Pods-ReduxPaperScissors-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 903CEE317084BB6CB96387F9B78CA921 /* Pods-ReduxPaperScissors-dummy.m */; }; 18 | 64D2DAB88803756E14994120C522E0E7 /* Pods-ReduxPaperScissors-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = A089DA0D18ADF921E674634D3146F262 /* Pods-ReduxPaperScissors-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | 6B3C4925172A4D953B62E8A256F9B5D3 /* TypeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83EDC964B22DDA588870C260A7A333C6 /* TypeHelper.swift */; }; 20 | 96B8735702CE951D765D9D9D86E7977A /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71271725DE5CCC0BBEE81EB8E9D98E82 /* Reducer.swift */; }; 21 | A58E9AAF933D99B386756292BD00E9B2 /* Pods-ReduxPaperScissorsTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 680B9A5A26FBBD3F168AEF97F1EE019D /* Pods-ReduxPaperScissorsTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 22 | AA326874B6A261E59715C7507F8A8753 /* ReSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2645AC457B419CE570365808349AA03C /* ReSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | AB6609FD51D6391E334DF58CC189C4D9 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CBAF76151CF858D574A099D1E7FC21 /* Store.swift */; }; 24 | BB96A0168CB88D0CC9C0BA63CF382158 /* DispatchingStoreType.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD6E955BFC89A34FDBF7FEE7631E7D19 /* DispatchingStoreType.swift */; }; 25 | BD48997F55FF7D28D697BF1A75511D63 /* StoreSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE64CEF372085B24E500493911C621F9 /* StoreSubscriber.swift */; }; 26 | BEB07E5C813E48009392A28E40198D65 /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79671FE58DCBAC8FB9711561D02ED4DA /* Coding.swift */; }; 27 | C0D5E5A4E3C3FC0F2EBC3C32D4F8CF92 /* Pods-ReduxPaperScissorsTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F716A802FF2809C8B3CE4EB7189E61B7 /* Pods-ReduxPaperScissorsTests-dummy.m */; }; 28 | D67495295A05A10E30947CBA7FAFF230 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */; }; 29 | D70008FDB37047621531BA80E157A7FA /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9FF8A70D2AC7A1D137462E1C3E5CB1 /* Subscription.swift */; }; 30 | F05B3F1C43999455FC9F4D4764A9C398 /* StoreType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6C9E17987035DE48EA9493A0C11119 /* StoreType.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 3AA2D26AA436CD50A66D3464F862D7B1 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 4C516032D858742BE3FA75429E39012C; 39 | remoteInfo = ReSwift; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXFileReference section */ 44 | 06A08ED341312030A5A2F345312A85BA /* Pods-ReduxPaperScissorsTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-ReduxPaperScissorsTests-acknowledgements.plist"; sourceTree = ""; }; 45 | 095003A1C8887429BB6F5FCCFFA68DB6 /* Pods-ReduxPaperScissors.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-ReduxPaperScissors.modulemap"; sourceTree = ""; }; 46 | 117411DD9F7B52110F3984C1ADBDABD1 /* Pods_ReduxPaperScissors.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_ReduxPaperScissors.framework; path = "Pods-ReduxPaperScissors.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 1CF2C289A75BE272C27ADA8712F61D70 /* Pods-ReduxPaperScissors-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReduxPaperScissors-frameworks.sh"; sourceTree = ""; }; 48 | 1F3C38E9357DF11B55A4279C68A73D47 /* Assertions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Assertions.swift; path = ReSwift/Utils/Assertions.swift; sourceTree = ""; }; 49 | 2645AC457B419CE570365808349AA03C /* ReSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ReSwift-umbrella.h"; sourceTree = ""; }; 50 | 2711A63FBF227A0CA669ED1D1EDB8F56 /* Action.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Action.swift; path = ReSwift/CoreTypes/Action.swift; sourceTree = ""; }; 51 | 294B3A1A02E1C0933D81049B00655C27 /* Pods-ReduxPaperScissors-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ReduxPaperScissors-acknowledgements.markdown"; sourceTree = ""; }; 52 | 2D0D744DB82063047CF5DCF1987208C0 /* Pods-ReduxPaperScissorsTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = "Pods-ReduxPaperScissorsTests.modulemap"; sourceTree = ""; }; 53 | 375E8868F8F6D6961F33EDED16FF1D5E /* State.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = State.swift; path = ReSwift/CoreTypes/State.swift; sourceTree = ""; }; 54 | 3BC289F3CA3C6CF07F492DDA4D060912 /* ReSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = ReSwift.framework; path = ReSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 3E7274F5C1701B4126FF7E3FFD10DA62 /* ReSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ReSwift-prefix.pch"; sourceTree = ""; }; 56 | 488ED670D0633EF8A7DAEBF63DEB5687 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 4D382FC2C97E84939F18CE497619CD05 /* Pods-ReduxPaperScissors.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReduxPaperScissors.debug.xcconfig"; sourceTree = ""; }; 58 | 5279BEEA93D3BB399FBCB375ADD3ACB4 /* ReSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ReSwift-dummy.m"; sourceTree = ""; }; 59 | 680B9A5A26FBBD3F168AEF97F1EE019D /* Pods-ReduxPaperScissorsTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ReduxPaperScissorsTests-umbrella.h"; sourceTree = ""; }; 60 | 710888D7209641BEAAC67A70485BE31B /* Pods-ReduxPaperScissorsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReduxPaperScissorsTests.debug.xcconfig"; sourceTree = ""; }; 61 | 71271725DE5CCC0BBEE81EB8E9D98E82 /* Reducer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reducer.swift; path = ReSwift/CoreTypes/Reducer.swift; sourceTree = ""; }; 62 | 76CD6DA36B8389315E498A6DD1542186 /* Pods-ReduxPaperScissorsTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-ReduxPaperScissorsTests-acknowledgements.markdown"; sourceTree = ""; }; 63 | 76DD018EBE9154131A62DBBCE936E7F5 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 79671FE58DCBAC8FB9711561D02ED4DA /* Coding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Coding.swift; path = ReSwift/Utils/Coding.swift; sourceTree = ""; }; 65 | 805B5FE4D9105698B18E093D10A1C5D2 /* Pods-ReduxPaperScissors.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReduxPaperScissors.release.xcconfig"; sourceTree = ""; }; 66 | 81CBAF76151CF858D574A099D1E7FC21 /* Store.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Store.swift; path = ReSwift/CoreTypes/Store.swift; sourceTree = ""; }; 67 | 8312E5EE24D06343FA7507EA5CAE7410 /* Pods-ReduxPaperScissorsTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-ReduxPaperScissorsTests.release.xcconfig"; sourceTree = ""; }; 68 | 83EDC964B22DDA588870C260A7A333C6 /* TypeHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TypeHelper.swift; path = ReSwift/Utils/TypeHelper.swift; sourceTree = ""; }; 69 | 8E6C9E17987035DE48EA9493A0C11119 /* StoreType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StoreType.swift; path = ReSwift/CoreTypes/StoreType.swift; sourceTree = ""; }; 70 | 903CEE317084BB6CB96387F9B78CA921 /* Pods-ReduxPaperScissors-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-ReduxPaperScissors-dummy.m"; sourceTree = ""; }; 71 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 72 | A089DA0D18ADF921E674634D3146F262 /* Pods-ReduxPaperScissors-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-ReduxPaperScissors-umbrella.h"; sourceTree = ""; }; 73 | A5ECA5B1093543DFD693B5985DE50C90 /* Pods-ReduxPaperScissors-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReduxPaperScissors-resources.sh"; sourceTree = ""; }; 74 | AD6E955BFC89A34FDBF7FEE7631E7D19 /* DispatchingStoreType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchingStoreType.swift; path = ReSwift/CoreTypes/DispatchingStoreType.swift; sourceTree = ""; }; 75 | AE64CEF372085B24E500493911C621F9 /* StoreSubscriber.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StoreSubscriber.swift; path = ReSwift/CoreTypes/StoreSubscriber.swift; sourceTree = ""; }; 76 | BDCC7F9B812EE18511022CF63922F8FF /* Pods-ReduxPaperScissors-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-ReduxPaperScissors-acknowledgements.plist"; sourceTree = ""; }; 77 | CBA73B0125641AA870FADDAE3918A7D9 /* Pods-ReduxPaperScissorsTests-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReduxPaperScissorsTests-resources.sh"; sourceTree = ""; }; 78 | CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 79 | CE9FF8A70D2AC7A1D137462E1C3E5CB1 /* Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Subscription.swift; path = ReSwift/CoreTypes/Subscription.swift; sourceTree = ""; }; 80 | D324436B2A4B19815F46B84BA55C72FC /* ReSwift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ReSwift.xcconfig; sourceTree = ""; }; 81 | D4873877D848E74EA3186C7044E7B498 /* ReSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; path = ReSwift.modulemap; sourceTree = ""; }; 82 | DBC367C3AAD96675383C816935AA7A1F /* Pods-ReduxPaperScissorsTests-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-ReduxPaperScissorsTests-frameworks.sh"; sourceTree = ""; }; 83 | DF0B6A341EF78D1C544EBE2156250467 /* Pods_ReduxPaperScissorsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_ReduxPaperScissorsTests.framework; path = "Pods-ReduxPaperScissorsTests.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | ED310EC73E16E3CFD27C99BFEDC3ECCD /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | F716A802FF2809C8B3CE4EB7189E61B7 /* Pods-ReduxPaperScissorsTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-ReduxPaperScissorsTests-dummy.m"; sourceTree = ""; }; 86 | FC871B7066428FF774C5F9208197F11C /* Middleware.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Middleware.swift; path = ReSwift/CoreTypes/Middleware.swift; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 63F97605616F066157D6797CB87A2810 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 3114D0D9947B4B9FAA0A8041E2410252 /* Foundation.framework in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | 763CD7CF58159A55757B704AF195387B /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | D67495295A05A10E30947CBA7FAFF230 /* Foundation.framework in Frameworks */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | E14EAB599398C14362246F85AD89F42D /* Frameworks */ = { 107 | isa = PBXFrameworksBuildPhase; 108 | buildActionMask = 2147483647; 109 | files = ( 110 | 2391BD100154145FE32BDAAA471D6E20 /* Foundation.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | /* End PBXFrameworksBuildPhase section */ 115 | 116 | /* Begin PBXGroup section */ 117 | 1334C0328849627CED539AF332118725 /* ReSwift */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 2711A63FBF227A0CA669ED1D1EDB8F56 /* Action.swift */, 121 | 1F3C38E9357DF11B55A4279C68A73D47 /* Assertions.swift */, 122 | 79671FE58DCBAC8FB9711561D02ED4DA /* Coding.swift */, 123 | AD6E955BFC89A34FDBF7FEE7631E7D19 /* DispatchingStoreType.swift */, 124 | FC871B7066428FF774C5F9208197F11C /* Middleware.swift */, 125 | 71271725DE5CCC0BBEE81EB8E9D98E82 /* Reducer.swift */, 126 | 375E8868F8F6D6961F33EDED16FF1D5E /* State.swift */, 127 | 81CBAF76151CF858D574A099D1E7FC21 /* Store.swift */, 128 | AE64CEF372085B24E500493911C621F9 /* StoreSubscriber.swift */, 129 | 8E6C9E17987035DE48EA9493A0C11119 /* StoreType.swift */, 130 | CE9FF8A70D2AC7A1D137462E1C3E5CB1 /* Subscription.swift */, 131 | 83EDC964B22DDA588870C260A7A333C6 /* TypeHelper.swift */, 132 | AD75C8AEA3D83979A2EAE74BD3957468 /* Support Files */, 133 | ); 134 | name = ReSwift; 135 | path = ReSwift; 136 | sourceTree = ""; 137 | }; 138 | 4E85699023F1A81FA7049626D6F4A25B /* Products */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 117411DD9F7B52110F3984C1ADBDABD1 /* Pods_ReduxPaperScissors.framework */, 142 | DF0B6A341EF78D1C544EBE2156250467 /* Pods_ReduxPaperScissorsTests.framework */, 143 | 3BC289F3CA3C6CF07F492DDA4D060912 /* ReSwift.framework */, 144 | ); 145 | name = Products; 146 | sourceTree = ""; 147 | }; 148 | 65B87757B472455AFA3007524A4E242F /* Targets Support Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | C3EA84C643983A125AFCB178A43988BD /* Pods-ReduxPaperScissors */, 152 | F9B664932A6504085158FE94BEE7C365 /* Pods-ReduxPaperScissorsTests */, 153 | ); 154 | name = "Targets Support Files"; 155 | sourceTree = ""; 156 | }; 157 | 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | CBB3DE36805AF21409EC968A9691732F /* Foundation.framework */, 161 | ); 162 | name = iOS; 163 | sourceTree = ""; 164 | }; 165 | 7DB346D0F39D3F0E887471402A8071AB = { 166 | isa = PBXGroup; 167 | children = ( 168 | 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */, 169 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */, 170 | A58919414556FF8285FCC0A42B1AC168 /* Pods */, 171 | 4E85699023F1A81FA7049626D6F4A25B /* Products */, 172 | 65B87757B472455AFA3007524A4E242F /* Targets Support Files */, 173 | ); 174 | sourceTree = ""; 175 | }; 176 | A58919414556FF8285FCC0A42B1AC168 /* Pods */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 1334C0328849627CED539AF332118725 /* ReSwift */, 180 | ); 181 | name = Pods; 182 | sourceTree = ""; 183 | }; 184 | AD75C8AEA3D83979A2EAE74BD3957468 /* Support Files */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 76DD018EBE9154131A62DBBCE936E7F5 /* Info.plist */, 188 | D4873877D848E74EA3186C7044E7B498 /* ReSwift.modulemap */, 189 | D324436B2A4B19815F46B84BA55C72FC /* ReSwift.xcconfig */, 190 | 5279BEEA93D3BB399FBCB375ADD3ACB4 /* ReSwift-dummy.m */, 191 | 3E7274F5C1701B4126FF7E3FFD10DA62 /* ReSwift-prefix.pch */, 192 | 2645AC457B419CE570365808349AA03C /* ReSwift-umbrella.h */, 193 | ); 194 | name = "Support Files"; 195 | path = "../Target Support Files/ReSwift"; 196 | sourceTree = ""; 197 | }; 198 | BC3CA7F9E30CC8F7E2DD044DD34432FC /* Frameworks */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 7531C8F8DE19F1AA3C8A7AC97A91DC29 /* iOS */, 202 | ); 203 | name = Frameworks; 204 | sourceTree = ""; 205 | }; 206 | C3EA84C643983A125AFCB178A43988BD /* Pods-ReduxPaperScissors */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | ED310EC73E16E3CFD27C99BFEDC3ECCD /* Info.plist */, 210 | 095003A1C8887429BB6F5FCCFFA68DB6 /* Pods-ReduxPaperScissors.modulemap */, 211 | 294B3A1A02E1C0933D81049B00655C27 /* Pods-ReduxPaperScissors-acknowledgements.markdown */, 212 | BDCC7F9B812EE18511022CF63922F8FF /* Pods-ReduxPaperScissors-acknowledgements.plist */, 213 | 903CEE317084BB6CB96387F9B78CA921 /* Pods-ReduxPaperScissors-dummy.m */, 214 | 1CF2C289A75BE272C27ADA8712F61D70 /* Pods-ReduxPaperScissors-frameworks.sh */, 215 | A5ECA5B1093543DFD693B5985DE50C90 /* Pods-ReduxPaperScissors-resources.sh */, 216 | A089DA0D18ADF921E674634D3146F262 /* Pods-ReduxPaperScissors-umbrella.h */, 217 | 4D382FC2C97E84939F18CE497619CD05 /* Pods-ReduxPaperScissors.debug.xcconfig */, 218 | 805B5FE4D9105698B18E093D10A1C5D2 /* Pods-ReduxPaperScissors.release.xcconfig */, 219 | ); 220 | name = "Pods-ReduxPaperScissors"; 221 | path = "Target Support Files/Pods-ReduxPaperScissors"; 222 | sourceTree = ""; 223 | }; 224 | F9B664932A6504085158FE94BEE7C365 /* Pods-ReduxPaperScissorsTests */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | 488ED670D0633EF8A7DAEBF63DEB5687 /* Info.plist */, 228 | 2D0D744DB82063047CF5DCF1987208C0 /* Pods-ReduxPaperScissorsTests.modulemap */, 229 | 76CD6DA36B8389315E498A6DD1542186 /* Pods-ReduxPaperScissorsTests-acknowledgements.markdown */, 230 | 06A08ED341312030A5A2F345312A85BA /* Pods-ReduxPaperScissorsTests-acknowledgements.plist */, 231 | F716A802FF2809C8B3CE4EB7189E61B7 /* Pods-ReduxPaperScissorsTests-dummy.m */, 232 | DBC367C3AAD96675383C816935AA7A1F /* Pods-ReduxPaperScissorsTests-frameworks.sh */, 233 | CBA73B0125641AA870FADDAE3918A7D9 /* Pods-ReduxPaperScissorsTests-resources.sh */, 234 | 680B9A5A26FBBD3F168AEF97F1EE019D /* Pods-ReduxPaperScissorsTests-umbrella.h */, 235 | 710888D7209641BEAAC67A70485BE31B /* Pods-ReduxPaperScissorsTests.debug.xcconfig */, 236 | 8312E5EE24D06343FA7507EA5CAE7410 /* Pods-ReduxPaperScissorsTests.release.xcconfig */, 237 | ); 238 | name = "Pods-ReduxPaperScissorsTests"; 239 | path = "Target Support Files/Pods-ReduxPaperScissorsTests"; 240 | sourceTree = ""; 241 | }; 242 | /* End PBXGroup section */ 243 | 244 | /* Begin PBXHeadersBuildPhase section */ 245 | 1BA84E10404BEA2F4B28FA85BBFD3C66 /* Headers */ = { 246 | isa = PBXHeadersBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | AA326874B6A261E59715C7507F8A8753 /* ReSwift-umbrella.h in Headers */, 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | }; 253 | 35FE833145FC75511BB0E4CB2F912763 /* Headers */ = { 254 | isa = PBXHeadersBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | A58E9AAF933D99B386756292BD00E9B2 /* Pods-ReduxPaperScissorsTests-umbrella.h in Headers */, 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | 57B86E0EDD9ADBDB48723AD9607B97B7 /* Headers */ = { 262 | isa = PBXHeadersBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | 64D2DAB88803756E14994120C522E0E7 /* Pods-ReduxPaperScissors-umbrella.h in Headers */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | /* End PBXHeadersBuildPhase section */ 270 | 271 | /* Begin PBXNativeTarget section */ 272 | 4C516032D858742BE3FA75429E39012C /* ReSwift */ = { 273 | isa = PBXNativeTarget; 274 | buildConfigurationList = 6565A02553A7EF05D27CCBC3894B9757 /* Build configuration list for PBXNativeTarget "ReSwift" */; 275 | buildPhases = ( 276 | AD6D5BA8DE0B78F5A6720525FD0DD26E /* Sources */, 277 | 763CD7CF58159A55757B704AF195387B /* Frameworks */, 278 | 1BA84E10404BEA2F4B28FA85BBFD3C66 /* Headers */, 279 | ); 280 | buildRules = ( 281 | ); 282 | dependencies = ( 283 | ); 284 | name = ReSwift; 285 | productName = ReSwift; 286 | productReference = 3BC289F3CA3C6CF07F492DDA4D060912 /* ReSwift.framework */; 287 | productType = "com.apple.product-type.framework"; 288 | }; 289 | 69BC39F711A9B2B72D654FC0500EFB26 /* Pods-ReduxPaperScissorsTests */ = { 290 | isa = PBXNativeTarget; 291 | buildConfigurationList = 9174DBF9134A352AF98A3BCB313B55B3 /* Build configuration list for PBXNativeTarget "Pods-ReduxPaperScissorsTests" */; 292 | buildPhases = ( 293 | C61A6E0F7874638F4BC025CD1CA0BA42 /* Sources */, 294 | E14EAB599398C14362246F85AD89F42D /* Frameworks */, 295 | 35FE833145FC75511BB0E4CB2F912763 /* Headers */, 296 | ); 297 | buildRules = ( 298 | ); 299 | dependencies = ( 300 | ); 301 | name = "Pods-ReduxPaperScissorsTests"; 302 | productName = "Pods-ReduxPaperScissorsTests"; 303 | productReference = DF0B6A341EF78D1C544EBE2156250467 /* Pods_ReduxPaperScissorsTests.framework */; 304 | productType = "com.apple.product-type.framework"; 305 | }; 306 | 9F861503F5BAE28B7606BDCD2F17F553 /* Pods-ReduxPaperScissors */ = { 307 | isa = PBXNativeTarget; 308 | buildConfigurationList = 7611C5FB859E09956E2C3718C4B7CDF3 /* Build configuration list for PBXNativeTarget "Pods-ReduxPaperScissors" */; 309 | buildPhases = ( 310 | 3C15711DE584064BDFC9BA1ABDF8AE19 /* Sources */, 311 | 63F97605616F066157D6797CB87A2810 /* Frameworks */, 312 | 57B86E0EDD9ADBDB48723AD9607B97B7 /* Headers */, 313 | ); 314 | buildRules = ( 315 | ); 316 | dependencies = ( 317 | 09F583BE762AB1DE5220E7F7C09C344F /* PBXTargetDependency */, 318 | ); 319 | name = "Pods-ReduxPaperScissors"; 320 | productName = "Pods-ReduxPaperScissors"; 321 | productReference = 117411DD9F7B52110F3984C1ADBDABD1 /* Pods_ReduxPaperScissors.framework */; 322 | productType = "com.apple.product-type.framework"; 323 | }; 324 | /* End PBXNativeTarget section */ 325 | 326 | /* Begin PBXProject section */ 327 | D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { 328 | isa = PBXProject; 329 | attributes = { 330 | LastSwiftUpdateCheck = 0730; 331 | LastUpgradeCheck = 0700; 332 | }; 333 | buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; 334 | compatibilityVersion = "Xcode 3.2"; 335 | developmentRegion = English; 336 | hasScannedForEncodings = 0; 337 | knownRegions = ( 338 | en, 339 | ); 340 | mainGroup = 7DB346D0F39D3F0E887471402A8071AB; 341 | productRefGroup = 4E85699023F1A81FA7049626D6F4A25B /* Products */; 342 | projectDirPath = ""; 343 | projectRoot = ""; 344 | targets = ( 345 | 9F861503F5BAE28B7606BDCD2F17F553 /* Pods-ReduxPaperScissors */, 346 | 69BC39F711A9B2B72D654FC0500EFB26 /* Pods-ReduxPaperScissorsTests */, 347 | 4C516032D858742BE3FA75429E39012C /* ReSwift */, 348 | ); 349 | }; 350 | /* End PBXProject section */ 351 | 352 | /* Begin PBXSourcesBuildPhase section */ 353 | 3C15711DE584064BDFC9BA1ABDF8AE19 /* Sources */ = { 354 | isa = PBXSourcesBuildPhase; 355 | buildActionMask = 2147483647; 356 | files = ( 357 | 608639A2B060F3A450E80F304766B83F /* Pods-ReduxPaperScissors-dummy.m in Sources */, 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | AD6D5BA8DE0B78F5A6720525FD0DD26E /* Sources */ = { 362 | isa = PBXSourcesBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | 1EA192E2FCD1B24CBF697C8D4A707CF4 /* Action.swift in Sources */, 366 | 48C00892E2C4B8EA57C3C91BA44F4E5E /* Assertions.swift in Sources */, 367 | BEB07E5C813E48009392A28E40198D65 /* Coding.swift in Sources */, 368 | BB96A0168CB88D0CC9C0BA63CF382158 /* DispatchingStoreType.swift in Sources */, 369 | 1639EB1ED7BCE62D9D8FECB54A95F904 /* Middleware.swift in Sources */, 370 | 96B8735702CE951D765D9D9D86E7977A /* Reducer.swift in Sources */, 371 | 44107B8D1D771E8620E2700D7E3D3843 /* ReSwift-dummy.m in Sources */, 372 | 2D7712B9C887214EEC565B50B3D506CE /* State.swift in Sources */, 373 | AB6609FD51D6391E334DF58CC189C4D9 /* Store.swift in Sources */, 374 | BD48997F55FF7D28D697BF1A75511D63 /* StoreSubscriber.swift in Sources */, 375 | F05B3F1C43999455FC9F4D4764A9C398 /* StoreType.swift in Sources */, 376 | D70008FDB37047621531BA80E157A7FA /* Subscription.swift in Sources */, 377 | 6B3C4925172A4D953B62E8A256F9B5D3 /* TypeHelper.swift in Sources */, 378 | ); 379 | runOnlyForDeploymentPostprocessing = 0; 380 | }; 381 | C61A6E0F7874638F4BC025CD1CA0BA42 /* Sources */ = { 382 | isa = PBXSourcesBuildPhase; 383 | buildActionMask = 2147483647; 384 | files = ( 385 | C0D5E5A4E3C3FC0F2EBC3C32D4F8CF92 /* Pods-ReduxPaperScissorsTests-dummy.m in Sources */, 386 | ); 387 | runOnlyForDeploymentPostprocessing = 0; 388 | }; 389 | /* End PBXSourcesBuildPhase section */ 390 | 391 | /* Begin PBXTargetDependency section */ 392 | 09F583BE762AB1DE5220E7F7C09C344F /* PBXTargetDependency */ = { 393 | isa = PBXTargetDependency; 394 | name = ReSwift; 395 | target = 4C516032D858742BE3FA75429E39012C /* ReSwift */; 396 | targetProxy = 3AA2D26AA436CD50A66D3464F862D7B1 /* PBXContainerItemProxy */; 397 | }; 398 | /* End PBXTargetDependency section */ 399 | 400 | /* Begin XCBuildConfiguration section */ 401 | 1392D57E030C4CB3034473A4C6F50AEA /* Debug */ = { 402 | isa = XCBuildConfiguration; 403 | baseConfigurationReference = D324436B2A4B19815F46B84BA55C72FC /* ReSwift.xcconfig */; 404 | buildSettings = { 405 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 406 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 407 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 408 | CURRENT_PROJECT_VERSION = 1; 409 | DEBUG_INFORMATION_FORMAT = dwarf; 410 | DEFINES_MODULE = YES; 411 | DYLIB_COMPATIBILITY_VERSION = 1; 412 | DYLIB_CURRENT_VERSION = 1; 413 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 414 | ENABLE_STRICT_OBJC_MSGSEND = YES; 415 | GCC_NO_COMMON_BLOCKS = YES; 416 | GCC_PREFIX_HEADER = "Target Support Files/ReSwift/ReSwift-prefix.pch"; 417 | INFOPLIST_FILE = "Target Support Files/ReSwift/Info.plist"; 418 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 419 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 420 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 421 | MODULEMAP_FILE = "Target Support Files/ReSwift/ReSwift.modulemap"; 422 | MTL_ENABLE_DEBUG_INFO = YES; 423 | PRODUCT_NAME = ReSwift; 424 | SDKROOT = iphoneos; 425 | SKIP_INSTALL = YES; 426 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 427 | SWIFT_VERSION = 3.0; 428 | TARGETED_DEVICE_FAMILY = "1,2"; 429 | VERSIONING_SYSTEM = "apple-generic"; 430 | VERSION_INFO_PREFIX = ""; 431 | }; 432 | name = Debug; 433 | }; 434 | 156284431C64CB05C59BDA0595A1E95A /* Release */ = { 435 | isa = XCBuildConfiguration; 436 | buildSettings = { 437 | ALWAYS_SEARCH_USER_PATHS = NO; 438 | CLANG_ANALYZER_NONNULL = YES; 439 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 440 | CLANG_CXX_LIBRARY = "libc++"; 441 | CLANG_ENABLE_MODULES = YES; 442 | CLANG_ENABLE_OBJC_ARC = YES; 443 | CLANG_WARN_BOOL_CONVERSION = YES; 444 | CLANG_WARN_CONSTANT_CONVERSION = YES; 445 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; 446 | CLANG_WARN_EMPTY_BODY = YES; 447 | CLANG_WARN_ENUM_CONVERSION = YES; 448 | CLANG_WARN_INT_CONVERSION = YES; 449 | CLANG_WARN_OBJC_ROOT_CLASS = YES; 450 | CLANG_WARN_UNREACHABLE_CODE = YES; 451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 452 | CODE_SIGNING_REQUIRED = NO; 453 | COPY_PHASE_STRIP = YES; 454 | ENABLE_NS_ASSERTIONS = NO; 455 | GCC_C_LANGUAGE_STANDARD = gnu99; 456 | GCC_PREPROCESSOR_DEFINITIONS = ( 457 | "POD_CONFIGURATION_RELEASE=1", 458 | "$(inherited)", 459 | ); 460 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 461 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 462 | GCC_WARN_UNDECLARED_SELECTOR = YES; 463 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 464 | GCC_WARN_UNUSED_FUNCTION = YES; 465 | GCC_WARN_UNUSED_VARIABLE = YES; 466 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 467 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; 468 | STRIP_INSTALLED_PRODUCT = NO; 469 | SYMROOT = "${SRCROOT}/../build"; 470 | VALIDATE_PRODUCT = YES; 471 | }; 472 | name = Release; 473 | }; 474 | 34BE90E2D5DEC2CE6679DDA4E886ED12 /* Release */ = { 475 | isa = XCBuildConfiguration; 476 | baseConfigurationReference = D324436B2A4B19815F46B84BA55C72FC /* ReSwift.xcconfig */; 477 | buildSettings = { 478 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 480 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 481 | CURRENT_PROJECT_VERSION = 1; 482 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 483 | DEFINES_MODULE = YES; 484 | DYLIB_COMPATIBILITY_VERSION = 1; 485 | DYLIB_CURRENT_VERSION = 1; 486 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 487 | ENABLE_STRICT_OBJC_MSGSEND = YES; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_PREFIX_HEADER = "Target Support Files/ReSwift/ReSwift-prefix.pch"; 490 | INFOPLIST_FILE = "Target Support Files/ReSwift/Info.plist"; 491 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 492 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 493 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 494 | MODULEMAP_FILE = "Target Support Files/ReSwift/ReSwift.modulemap"; 495 | MTL_ENABLE_DEBUG_INFO = NO; 496 | PRODUCT_NAME = ReSwift; 497 | SDKROOT = iphoneos; 498 | SKIP_INSTALL = YES; 499 | SWIFT_VERSION = 3.0; 500 | TARGETED_DEVICE_FAMILY = "1,2"; 501 | VERSIONING_SYSTEM = "apple-generic"; 502 | VERSION_INFO_PREFIX = ""; 503 | }; 504 | name = Release; 505 | }; 506 | 38F46765A6DEB362D7A310712927F295 /* Debug */ = { 507 | isa = XCBuildConfiguration; 508 | baseConfigurationReference = 4D382FC2C97E84939F18CE497619CD05 /* Pods-ReduxPaperScissors.debug.xcconfig */; 509 | buildSettings = { 510 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 511 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 512 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 513 | CURRENT_PROJECT_VERSION = 1; 514 | DEBUG_INFORMATION_FORMAT = dwarf; 515 | DEFINES_MODULE = YES; 516 | DYLIB_COMPATIBILITY_VERSION = 1; 517 | DYLIB_CURRENT_VERSION = 1; 518 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 519 | ENABLE_STRICT_OBJC_MSGSEND = YES; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | INFOPLIST_FILE = "Target Support Files/Pods-ReduxPaperScissors/Info.plist"; 522 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 523 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 524 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 525 | MACH_O_TYPE = staticlib; 526 | MODULEMAP_FILE = "Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.modulemap"; 527 | MTL_ENABLE_DEBUG_INFO = YES; 528 | OTHER_LDFLAGS = ""; 529 | OTHER_LIBTOOLFLAGS = ""; 530 | PODS_ROOT = "$(SRCROOT)"; 531 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 532 | PRODUCT_NAME = Pods_ReduxPaperScissors; 533 | SDKROOT = iphoneos; 534 | SKIP_INSTALL = YES; 535 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 536 | TARGETED_DEVICE_FAMILY = "1,2"; 537 | VERSIONING_SYSTEM = "apple-generic"; 538 | VERSION_INFO_PREFIX = ""; 539 | }; 540 | name = Debug; 541 | }; 542 | 43CBFE71C9B765089558240FD8F80D96 /* Debug */ = { 543 | isa = XCBuildConfiguration; 544 | baseConfigurationReference = 710888D7209641BEAAC67A70485BE31B /* Pods-ReduxPaperScissorsTests.debug.xcconfig */; 545 | buildSettings = { 546 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 547 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 548 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 549 | CURRENT_PROJECT_VERSION = 1; 550 | DEBUG_INFORMATION_FORMAT = dwarf; 551 | DEFINES_MODULE = YES; 552 | DYLIB_COMPATIBILITY_VERSION = 1; 553 | DYLIB_CURRENT_VERSION = 1; 554 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 555 | ENABLE_STRICT_OBJC_MSGSEND = YES; 556 | GCC_NO_COMMON_BLOCKS = YES; 557 | INFOPLIST_FILE = "Target Support Files/Pods-ReduxPaperScissorsTests/Info.plist"; 558 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 559 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 560 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 561 | MACH_O_TYPE = staticlib; 562 | MODULEMAP_FILE = "Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.modulemap"; 563 | MTL_ENABLE_DEBUG_INFO = YES; 564 | OTHER_LDFLAGS = ""; 565 | OTHER_LIBTOOLFLAGS = ""; 566 | PODS_ROOT = "$(SRCROOT)"; 567 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 568 | PRODUCT_NAME = Pods_ReduxPaperScissorsTests; 569 | SDKROOT = iphoneos; 570 | SKIP_INSTALL = YES; 571 | TARGETED_DEVICE_FAMILY = "1,2"; 572 | VERSIONING_SYSTEM = "apple-generic"; 573 | VERSION_INFO_PREFIX = ""; 574 | }; 575 | name = Debug; 576 | }; 577 | B14339D592D173B440EC03BC52B8124E /* Release */ = { 578 | isa = XCBuildConfiguration; 579 | baseConfigurationReference = 8312E5EE24D06343FA7507EA5CAE7410 /* Pods-ReduxPaperScissorsTests.release.xcconfig */; 580 | buildSettings = { 581 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 582 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 583 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 584 | CURRENT_PROJECT_VERSION = 1; 585 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 586 | DEFINES_MODULE = YES; 587 | DYLIB_COMPATIBILITY_VERSION = 1; 588 | DYLIB_CURRENT_VERSION = 1; 589 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 590 | ENABLE_STRICT_OBJC_MSGSEND = YES; 591 | GCC_NO_COMMON_BLOCKS = YES; 592 | INFOPLIST_FILE = "Target Support Files/Pods-ReduxPaperScissorsTests/Info.plist"; 593 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 594 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 595 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 596 | MACH_O_TYPE = staticlib; 597 | MODULEMAP_FILE = "Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.modulemap"; 598 | MTL_ENABLE_DEBUG_INFO = NO; 599 | OTHER_LDFLAGS = ""; 600 | OTHER_LIBTOOLFLAGS = ""; 601 | PODS_ROOT = "$(SRCROOT)"; 602 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 603 | PRODUCT_NAME = Pods_ReduxPaperScissorsTests; 604 | SDKROOT = iphoneos; 605 | SKIP_INSTALL = YES; 606 | TARGETED_DEVICE_FAMILY = "1,2"; 607 | VERSIONING_SYSTEM = "apple-generic"; 608 | VERSION_INFO_PREFIX = ""; 609 | }; 610 | name = Release; 611 | }; 612 | C382132BB6BF8CA1A911872A2062FD0D /* Debug */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ALWAYS_SEARCH_USER_PATHS = NO; 616 | CLANG_ANALYZER_NONNULL = YES; 617 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 618 | CLANG_CXX_LIBRARY = "libc++"; 619 | CLANG_ENABLE_MODULES = YES; 620 | CLANG_ENABLE_OBJC_ARC = YES; 621 | CLANG_WARN_BOOL_CONVERSION = YES; 622 | CLANG_WARN_CONSTANT_CONVERSION = YES; 623 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; 624 | CLANG_WARN_EMPTY_BODY = YES; 625 | CLANG_WARN_ENUM_CONVERSION = YES; 626 | CLANG_WARN_INT_CONVERSION = YES; 627 | CLANG_WARN_OBJC_ROOT_CLASS = YES; 628 | CLANG_WARN_UNREACHABLE_CODE = YES; 629 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 630 | CODE_SIGNING_REQUIRED = NO; 631 | COPY_PHASE_STRIP = NO; 632 | ENABLE_TESTABILITY = YES; 633 | GCC_C_LANGUAGE_STANDARD = gnu99; 634 | GCC_DYNAMIC_NO_PIC = NO; 635 | GCC_OPTIMIZATION_LEVEL = 0; 636 | GCC_PREPROCESSOR_DEFINITIONS = ( 637 | "POD_CONFIGURATION_DEBUG=1", 638 | "DEBUG=1", 639 | "$(inherited)", 640 | ); 641 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 642 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 643 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 644 | GCC_WARN_UNDECLARED_SELECTOR = YES; 645 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 646 | GCC_WARN_UNUSED_FUNCTION = YES; 647 | GCC_WARN_UNUSED_VARIABLE = YES; 648 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 649 | ONLY_ACTIVE_ARCH = YES; 650 | PROVISIONING_PROFILE_SPECIFIER = NO_SIGNING/; 651 | STRIP_INSTALLED_PRODUCT = NO; 652 | SYMROOT = "${SRCROOT}/../build"; 653 | }; 654 | name = Debug; 655 | }; 656 | F273D08691C5E3A18C4015108B647C98 /* Release */ = { 657 | isa = XCBuildConfiguration; 658 | baseConfigurationReference = 805B5FE4D9105698B18E093D10A1C5D2 /* Pods-ReduxPaperScissors.release.xcconfig */; 659 | buildSettings = { 660 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 661 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 662 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 663 | CURRENT_PROJECT_VERSION = 1; 664 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 665 | DEFINES_MODULE = YES; 666 | DYLIB_COMPATIBILITY_VERSION = 1; 667 | DYLIB_CURRENT_VERSION = 1; 668 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 669 | ENABLE_STRICT_OBJC_MSGSEND = YES; 670 | GCC_NO_COMMON_BLOCKS = YES; 671 | INFOPLIST_FILE = "Target Support Files/Pods-ReduxPaperScissors/Info.plist"; 672 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 673 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 674 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 675 | MACH_O_TYPE = staticlib; 676 | MODULEMAP_FILE = "Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.modulemap"; 677 | MTL_ENABLE_DEBUG_INFO = NO; 678 | OTHER_LDFLAGS = ""; 679 | OTHER_LIBTOOLFLAGS = ""; 680 | PODS_ROOT = "$(SRCROOT)"; 681 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; 682 | PRODUCT_NAME = Pods_ReduxPaperScissors; 683 | SDKROOT = iphoneos; 684 | SKIP_INSTALL = YES; 685 | TARGETED_DEVICE_FAMILY = "1,2"; 686 | VERSIONING_SYSTEM = "apple-generic"; 687 | VERSION_INFO_PREFIX = ""; 688 | }; 689 | name = Release; 690 | }; 691 | /* End XCBuildConfiguration section */ 692 | 693 | /* Begin XCConfigurationList section */ 694 | 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { 695 | isa = XCConfigurationList; 696 | buildConfigurations = ( 697 | C382132BB6BF8CA1A911872A2062FD0D /* Debug */, 698 | 156284431C64CB05C59BDA0595A1E95A /* Release */, 699 | ); 700 | defaultConfigurationIsVisible = 0; 701 | defaultConfigurationName = Release; 702 | }; 703 | 6565A02553A7EF05D27CCBC3894B9757 /* Build configuration list for PBXNativeTarget "ReSwift" */ = { 704 | isa = XCConfigurationList; 705 | buildConfigurations = ( 706 | 1392D57E030C4CB3034473A4C6F50AEA /* Debug */, 707 | 34BE90E2D5DEC2CE6679DDA4E886ED12 /* Release */, 708 | ); 709 | defaultConfigurationIsVisible = 0; 710 | defaultConfigurationName = Release; 711 | }; 712 | 7611C5FB859E09956E2C3718C4B7CDF3 /* Build configuration list for PBXNativeTarget "Pods-ReduxPaperScissors" */ = { 713 | isa = XCConfigurationList; 714 | buildConfigurations = ( 715 | 38F46765A6DEB362D7A310712927F295 /* Debug */, 716 | F273D08691C5E3A18C4015108B647C98 /* Release */, 717 | ); 718 | defaultConfigurationIsVisible = 0; 719 | defaultConfigurationName = Release; 720 | }; 721 | 9174DBF9134A352AF98A3BCB313B55B3 /* Build configuration list for PBXNativeTarget "Pods-ReduxPaperScissorsTests" */ = { 722 | isa = XCConfigurationList; 723 | buildConfigurations = ( 724 | 43CBFE71C9B765089558240FD8F80D96 /* Debug */, 725 | B14339D592D173B440EC03BC52B8124E /* Release */, 726 | ); 727 | defaultConfigurationIsVisible = 0; 728 | defaultConfigurationName = Release; 729 | }; 730 | /* End XCConfigurationList section */ 731 | }; 732 | rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; 733 | } 734 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 ReSwift Contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/README.md: -------------------------------------------------------------------------------- 1 | # ReSwift 2 | 3 | [![Build Status](https://img.shields.io/travis/ReSwift/ReSwift/master.svg?style=flat-square)](https://travis-ci.org/ReSwift/ReSwift) [![Code coverage status](https://img.shields.io/codecov/c/github/ReSwift/ReSwift.svg?style=flat-square)](http://codecov.io/github/ReSwift/ReSwift) [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/ReSwift.svg?style=flat-square)](https://cocoapods.org/pods/ReSwift) [![Platform support](https://img.shields.io/badge/platform-ios%20%7C%20osx%20%7C%20tvos%20%7C%20watchos-lightgrey.svg?style=flat-square)](https://github.com/ReSwift/ReSwift/blob/master/LICENSE.md) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/ReSwift/ReSwift/blob/master/LICENSE.md) 4 | 5 | **Supported Swift Version:**: Swift 3.0.1 6 | For Swift 2.2 Support use [Release 2.0.0](https://github.com/ReSwift/ReSwift/releases/tag/2.0.0) or earlier. 7 | 8 | # Introduction 9 | 10 | ReSwift is a [Redux](https://github.com/reactjs/redux)-like implementation of the unidirectional data flow architecture in Swift. ReSwift helps you to separate three important concerns of your app's components: 11 | 12 | - **State**: in a ReSwift app the entire app state is explicitly stored in a data structure. This helps avoid complicated state management code, enables better debugging and has many, many more benefits... 13 | - **Views**: in a ReSwift app your views update when your state changes. Your views become simple visualizations of the current app state. 14 | - **State Changes**: in a ReSwift app you can only perform state changes through actions. Actions are small pieces of data that describe a state change. By drastically limiting the way state can be mutated, your app becomes easier to understand and it gets easier to work with many collaborators. 15 | 16 | The ReSwift library is tiny - allowing users to dive into the code, understand every single line and [hopefully contribute](#contributing). 17 | 18 | ReSwift is quickly growing beyond the core library, providing experimental extensions for routing and time traveling through past app states! 19 | 20 | Excited? So are we 🎉 21 | 22 | Check out our [public gitter chat!](https://gitter.im/ReSwift/public) 23 | 24 | # Table of Contents 25 | 26 | - [About ReSwift](#about-reswift) 27 | - [Why ReSwift?](#why-reswift) 28 | - [Getting Started Guide](#getting-started-guide) 29 | - [Installation](#installation) 30 | - [Testing](#testing) 31 | - [Checking Out Source Code](#checking-out-source-code) 32 | - [Demo](#demo) 33 | - [Extensions](#extensions) 34 | - [Example Projects](#example-projects) 35 | - [Contributing](#contributing) 36 | - [Credits](#credits) 37 | - [Get in touch](#get-in-touch) 38 | 39 | # About ReSwift 40 | 41 | ReSwift relies on a few principles: 42 | - **The Store** stores your entire app state in the form of a single data structure. This state can only be modified by dispatching Actions to the store. Whenever the state in the store changes, the store will notify all observers. 43 | - **Actions** are a declarative way of describing a state change. Actions don't contain any code, they are consumed by the store and forwarded to reducers. Reducers will handle the actions by implementing a different state change for each action. 44 | - **Reducers** provide pure functions, that based on the current action and the current app state, create a new app state 45 | 46 | ![](Docs/img/reswift_concept.png) 47 | 48 | For a very simple app, that maintains a counter that can be increased and decreased, you can define the app state as following: 49 | 50 | ```swift 51 | struct AppState: StateType { 52 | var counter: Int = 0 53 | } 54 | ``` 55 | 56 | You would also define two actions, one for increasing and one for decreasing the counter. In the [Getting Started Guide](http://reswift.github.io/ReSwift/master/getting-started-guide.html) you can find out how to construct complex actions. For the simple actions in this example we can define empty structs that conform to action: 57 | 58 | ```swift 59 | struct CounterActionIncrease: Action {} 60 | struct CounterActionDecrease: Action {} 61 | ``` 62 | 63 | Your reducer needs to respond to these different action types, that can be done by switching over the type of action: 64 | 65 | ```swift 66 | func counterReducer(action: Action, state: AppState?) -> AppState { 67 | var state = state ?? AppState() 68 | 69 | switch action { 70 | case _ as CounterActionIncrease: 71 | state.counter += 1 72 | case _ as CounterActionDecrease: 73 | state.counter -= 1 74 | default: 75 | break 76 | } 77 | 78 | return state 79 | } 80 | ``` 81 | In order to have a predictable app state, it is important that the reducer is always free of side effects, it receives the current app state and an action and returns the new app state. 82 | 83 | To maintain our state and delegate the actions to the reducers, we need a store. Let's call it `mainStore` and define it as a global constant, for example in the app delegate file: 84 | 85 | ```swift 86 | let mainStore = Store( 87 | reducer: counterReducer, 88 | state: nil 89 | ) 90 | 91 | @UIApplicationMain 92 | class AppDelegate: UIResponder, UIApplicationDelegate { 93 | [...] 94 | } 95 | ``` 96 | 97 | 98 | Lastly, your view layer, in this case a view controller, needs to tie into this system by subscribing to store updates and emitting actions whenever the app state needs to be changed: 99 | 100 | ```swift 101 | class CounterViewController: UIViewController, StoreSubscriber { 102 | 103 | @IBOutlet var counterLabel: UILabel! 104 | 105 | override func viewWillAppear(animated: Bool) { 106 | mainStore.subscribe(self) 107 | } 108 | 109 | override func viewWillDisappear(animated: Bool) { 110 | mainStore.unsubscribe(self) 111 | } 112 | 113 | func newState(state: AppState) { 114 | counterLabel.text = "\(state.counter)" 115 | } 116 | 117 | @IBAction func increaseButtonTapped(sender: UIButton) { 118 | mainStore.dispatch( 119 | CounterActionIncrease() 120 | ) 121 | } 122 | 123 | @IBAction func decreaseButtonTapped(sender: UIButton) { 124 | mainStore.dispatch( 125 | CounterActionDecrease() 126 | ) 127 | } 128 | 129 | } 130 | ``` 131 | 132 | The `newState` method will be called by the `Store` whenever a new app state is available, this is where we need to adjust our view to reflect the latest app state. 133 | 134 | Button taps result in dispatched actions that will be handled by the store and its reducers, resulting in a new app state. 135 | 136 | This is a very basic example that only shows a subset of ReSwift's features, read the Getting Started Guide to see how you can build entire apps with this architecture. For a complete implementation of this example see the [CounterExample](https://github.com/ReSwift/CounterExample) project. 137 | 138 | [You can also watch this talk on the motivation behind ReSwift](https://realm.io/news/benji-encz-unidirectional-data-flow-swift/). 139 | 140 | # Why ReSwift? 141 | 142 | Model-View-Controller (MVC) is not a holistic application architecture. Typical Cocoa apps defer a lot of complexity to controllers since MVC doesn't offer other solutions for state management, one of the most complex issues in app development. 143 | 144 | Apps built upon MVC often end up with a lot of complexity around state management and propagation. We need to use callbacks, delegations, Key-Value-Observation and notifications to pass information around in our apps and to ensure that all the relevant views have the latest state. 145 | 146 | This approach involves a lot of manual steps and is thus error prone and doesn't scale well in complex code bases. 147 | 148 | It also leads to code that is difficult to understand at a glance, since dependencies can be hidden deep inside of view controllers. Lastly, you mostly end up with inconsistent code, where each developer uses the state propagation procedure they personally prefer. You can circumvent this issue by style guides and code reviews but you cannot automatically verify the adherence to these guidelines. 149 | 150 | ReSwift attempts to solve these problem by placing strong constraints on the way applications can be written. This reduces the room for programmer error and leads to applications that can be easily understood - by inspecting the application state data structure, the actions and the reducers. 151 | 152 | This architecture provides further benefits beyond improving your code base: 153 | 154 | - Stores, Reducers, Actions and extensions such as ReSwift Router are entirely platform independent - you can easily use the same business logic and share it between apps for multiple platforms (iOS, tvOS, etc.) 155 | - Want to collaborate with a co-worker on fixing an app crash? Use [ReSwift Recorder](https://github.com/ReSwift/ReSwift-Recorder) to record the actions that lead up to the crash and send them the JSON file so that they can replay the actions and reproduce the issue right away. 156 | - Maybe recorded actions can be used to build UI and integration tests? 157 | 158 | The ReSwift tooling is still in a very early stage, but aforementioned prospects excite me and hopefully others in the community as well! 159 | 160 | # Getting Started Guide 161 | 162 | [A Getting Started Guide that describes the core components of apps built with ReSwift lives here](http://reswift.github.io/ReSwift/master/getting-started-guide.html). It will be expanded in the next few weeks. To get an understanding of the core principles we recommend reading the brilliant [redux documentation](http://redux.js.org/). 163 | 164 | # Installation 165 | 166 | ## CocoaPods 167 | 168 | You can install ReSwift via CocoaPods by adding it to your `Podfile`: 169 | ``` 170 | use_frameworks! 171 | 172 | source 'https://github.com/CocoaPods/Specs.git' 173 | platform :ios, '8.0' 174 | 175 | pod 'ReSwift' 176 | ``` 177 | 178 | And run `pod install`. 179 | 180 | ## Carthage 181 | 182 | You can install ReSwift via [Carthage](https://github.com/Carthage/Carthage) by adding the following line to your `Cartfile`: 183 | 184 | ``` 185 | github "ReSwift/ReSwift" 186 | ``` 187 | 188 | ## Swift Package Manager 189 | 190 | You can install ReSwift via [Swift Package Manager](https://swift.org/package-manager/) by adding the following line to your `Package.swift`: 191 | 192 | ```swift 193 | import PackageDescription 194 | 195 | let package = Package( 196 | [...] 197 | dependencies: [ 198 | .Package(url: "https://github.com/ReSwift/ReSwift.git", majorVersion: XYZ) 199 | ] 200 | ) 201 | ``` 202 | 203 | # Checking out Source Code 204 | 205 | After checking out the project run `pod install` to get the latest supported version of [SwiftLint](https://github.com/realm/SwiftLint), which we use to ensure a consistent style in the codebase. 206 | 207 | # Demo 208 | 209 | Using this library you can implement apps that have an explicit, reproducible state, allowing you, among many other things, to replay and rewind the app state, as shown below: 210 | 211 | ![](Docs/img/timetravel.gif) 212 | 213 | # Extensions 214 | 215 | This repository contains the core component for ReSwift, the following extensions are available: 216 | 217 | - [ReSwift-Router](https://github.com/ReSwift/ReSwift-Router): Provides a ReSwift compatible Router that allows declarative routing in iOS applications 218 | - [ReSwift-Recorder](https://github.com/ReSwift/ReSwift-Recorder): Provides a `Store` implementation that records all `Action`s and allows for hot-reloading and time travel 219 | 220 | # Example Projects 221 | 222 | - [CounterExample](https://github.com/ReSwift/CounterExample): A very simple counter app implemented with ReSwift. 223 | - [CounterExample-Navigation-TimeTravel](https://github.com/ReSwift/CounterExample-Navigation-TimeTravel): This example builds on the simple CounterExample app, adding time travel with [ReSwiftRecorder](https://github.com/ReSwift/ReSwift-Recorder) and routing with [ReSwiftRouter](https://github.com/ReSwift/ReSwift-Router). 224 | - [GitHubBrowserExample](https://github.com/ReSwift/GitHubBrowserExample): A real world example, involving authentication, network requests and navigation. Still WIP but should be the best resource for starting to adapt `ReSwift` in your own app. 225 | - [Meet](https://github.com/Ben-G/Meet): A real world application being built with ReSwift - currently still very early on. It is not up to date with the latest version of ReSwift, but is the best project for demonstrating time travel. 226 | 227 | ## Production Apps with Open Source Code 228 | 229 | - [Product Hunt for OS X](https://github.com/producthunt/producthunt-osx) Official Product Hunt client for OS X. 230 | 231 | # Contributing 232 | 233 | There's still a lot of work to do here! We would love to see you involved! You can find all the details on how to get started in the [Contributing Guide](/CONTRIBUTING.md). 234 | 235 | # Credits 236 | 237 | - Thanks a lot to [Dan Abramov](https://github.com/gaearon) for building [Redux](https://github.com/reactjs/redux) - all ideas in here and many implementation details were provided by his library. 238 | 239 | # Get in touch 240 | 241 | If you have any questions, you can find the core team on twitter: 242 | 243 | - [@benjaminencz](https://twitter.com/benjaminencz) 244 | - [@karlbowden](https://twitter.com/karlbowden) 245 | - [@ARendtslev](https://twitter.com/ARendtslev) 246 | - [@ctietze](https://twitter.com/ctietze) 247 | - [@mjarvis](https://twitter.com/mjarvis) 248 | 249 | We also have a [public gitter chat!](https://gitter.im/ReSwift/public) 250 | 251 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/Action.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Action.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 12/14/15. 6 | // Copyright © 2015 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | /** 11 | This is ReSwift's built in action type, it is the only built in type that conforms to the 12 | `Action` protocol. `StandardAction` can be serialized and can therefore be used with developer 13 | tools that restore state between app launches. 14 | 15 | The downside of `StandardAction` is that it carries its payload as an untyped dictionary which does 16 | not play well with Swift's type system. 17 | 18 | It is recommended that you define your own types that conform to `Action` - if you want to be able 19 | to serialize your custom action types, you can implement `StandardActionConvertible` which will 20 | make it possible to generate a `StandardAction` from your typed action - the best of both worlds! 21 | */ 22 | public struct StandardAction: Action { 23 | /// A String that identifies the type of this `StandardAction` 24 | public let type: String 25 | /// An untyped, JSON-compatible payload 26 | public let payload: [String: AnyObject]? 27 | /// Indicates whether this action will be deserialized as a typed action or as a standard action 28 | public let isTypedAction: Bool 29 | 30 | /** 31 | Initializes this `StandardAction` with a type, a payload and information about whether this is 32 | a typed action or not. 33 | 34 | - parameter type: String representation of the Action type 35 | - parameter payload: Payload convertable to JSON 36 | - parameter isTypedAction: Is Action a subclassed type 37 | */ 38 | public init(type: String, payload: [String: AnyObject]? = nil, isTypedAction: Bool = false) { 39 | self.type = type 40 | self.payload = payload 41 | self.isTypedAction = isTypedAction 42 | } 43 | } 44 | 45 | // MARK: Coding Extension 46 | 47 | private let typeKey = "type" 48 | private let payloadKey = "payload" 49 | private let isTypedActionKey = "isTypedAction" 50 | let reSwiftNull = "ReSwift_Null" 51 | 52 | extension StandardAction: Coding { 53 | 54 | public init?(dictionary: [String: AnyObject]) { 55 | guard let type = dictionary[typeKey] as? String, 56 | let isTypedAction = dictionary[isTypedActionKey] as? Bool else { return nil } 57 | self.type = type 58 | self.payload = dictionary[payloadKey] as? [String: AnyObject] 59 | self.isTypedAction = isTypedAction 60 | } 61 | 62 | public var dictionaryRepresentation: [String: AnyObject] { 63 | let payload: AnyObject = self.payload as AnyObject? ?? reSwiftNull as AnyObject 64 | 65 | return [typeKey: type as NSString, 66 | payloadKey: payload, 67 | isTypedActionKey: isTypedAction as NSNumber] 68 | } 69 | } 70 | 71 | /// Implement this protocol on your custom `Action` type if you want to make the action 72 | /// serializable. 73 | /// - Note: We are working on a tool to automatically generate the implementation of this protocol 74 | /// for your custom action types. 75 | public protocol StandardActionConvertible: Action { 76 | /** 77 | Within this initializer you need to use the payload from the `StandardAction` to configure the 78 | state of your custom action type. 79 | 80 | Example: 81 | 82 | ``` 83 | init(_ standardAction: StandardAction) { 84 | self.twitterUser = decode(standardAction.payload!["twitterUser"]!) 85 | } 86 | ``` 87 | 88 | - Note: If you, as most developers, only use action serialization/deserialization during 89 | development, you can feel free to use the unsafe `!` operator. 90 | */ 91 | init (_ standardAction: StandardAction) 92 | 93 | /** 94 | Use the information from your custom action to generate a `StandardAction`. The `type` of the 95 | StandardAction should typically match the type name of your custom action type. You also need 96 | to set `isTypedAction` to `true`. Use the information from your action's properties to 97 | configure the payload of the `StandardAction`. 98 | 99 | Example: 100 | 101 | ``` 102 | func toStandardAction() -> StandardAction { 103 | let payload = ["twitterUser": encode(self.twitterUser)] 104 | 105 | return StandardAction(type: SearchTwitterScene.SetSelectedTwitterUser.type, 106 | payload: payload, isTypedAction: true) 107 | } 108 | ``` 109 | 110 | */ 111 | func toStandardAction() -> StandardAction 112 | } 113 | 114 | /// All actions that want to be able to be dispatched to a store need to conform to this protocol 115 | /// Currently it is just a marker protocol with no requirements. 116 | public protocol Action { } 117 | 118 | /// Initial Action that is dispatched as soon as the store is created. 119 | /// Reducers respond to this action by configuring their intial state. 120 | public struct ReSwiftInit: Action {} 121 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/DispatchingStoreType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Defines the interface of a dispatching, stateless Store in ReSwift. `StoreType` is 5 | the default usage of this interface. Can be used for store variables where you don't 6 | care about the state, but want to be able to dispatch actions. 7 | */ 8 | public protocol DispatchingStoreType { 9 | 10 | /** 11 | Dispatches an action. This is the simplest way to modify the stores state. 12 | 13 | Example of dispatching an action: 14 | 15 | ``` 16 | store.dispatch( CounterAction.IncreaseCounter ) 17 | ``` 18 | 19 | - parameter action: The action that is being dispatched to the store 20 | - returns: By default returns the dispatched action, but middlewares can change the 21 | return type, e.g. to return promises 22 | */ 23 | func dispatch(_ action: Action) 24 | } 25 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/Middleware.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Middleware.swift 3 | // ReSwift 4 | // 5 | // Created by Benji Encz on 12/24/15. 6 | // Copyright © 2015 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias DispatchFunction = (Action) -> Void 12 | public typealias Middleware = (@escaping DispatchFunction, @escaping () -> State?) 13 | -> (@escaping DispatchFunction) -> DispatchFunction 14 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/Reducer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reducer.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 12/14/15. 6 | // Copyright © 2015 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public typealias Reducer = 12 | (_ action: Action, _ state: ReducerStateType?) -> ReducerStateType 13 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/State.swift: -------------------------------------------------------------------------------- 1 | // 2 | // State.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 12/14/15. 6 | // Copyright © 2015 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol StateType { } 12 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/Store.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Store.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 11/11/15. 6 | // Copyright © 2015 DigiTales. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | This class is the default implementation of the `Store` protocol. You will use this store in most 13 | of your applications. You shouldn't need to implement your own store. 14 | You initialize the store with a reducer and an initial application state. If your app has multiple 15 | reducers you can combine them by initializng a `MainReducer` with all of your reducers as an 16 | argument. 17 | */ 18 | open class Store: StoreType { 19 | 20 | typealias SubscriptionType = SubscriptionBox 21 | 22 | // swiftlint:disable todo 23 | // TODO: Setter should not be public; need way for store enhancers to modify appState anyway 24 | // swiftlint:enable todo 25 | 26 | /*private (set)*/ public var state: State! { 27 | didSet { 28 | subscriptions = subscriptions.filter { $0.subscriber != nil } 29 | subscriptions.forEach { 30 | $0.newValues(oldState: oldValue, newState: state) 31 | } 32 | } 33 | } 34 | 35 | public var dispatchFunction: DispatchFunction! 36 | 37 | private var reducer: Reducer 38 | 39 | var subscriptions: [SubscriptionType] = [] 40 | 41 | private var isDispatching = false 42 | 43 | public required init( 44 | reducer: @escaping Reducer, 45 | state: State?, 46 | middleware: [Middleware] = [] 47 | ) { 48 | self.reducer = reducer 49 | 50 | // Wrap the dispatch function with all middlewares 51 | self.dispatchFunction = middleware 52 | .reversed() 53 | .reduce({ [unowned self] action in 54 | return self._defaultDispatch(action: action) 55 | }) { dispatchFunction, middleware in 56 | // If the store get's deinitialized before the middleware is complete; drop 57 | // the action without dispatching. 58 | let dispatch: (Action) -> Void = { [weak self] in self?.dispatch($0) } 59 | let getState = { [weak self] in self?.state } 60 | return middleware(dispatch, getState)(dispatchFunction) 61 | } 62 | 63 | if let state = state { 64 | self.state = state 65 | } else { 66 | dispatch(ReSwiftInit()) 67 | } 68 | } 69 | 70 | open func subscribe(_ subscriber: S) 71 | where S.StoreSubscriberStateType == State { 72 | _ = subscribe(subscriber, transform: nil) 73 | } 74 | 75 | open func subscribe( 76 | _ subscriber: S, transform: ((Subscription) -> Subscription)? 77 | ) where S.StoreSubscriberStateType == SelectedState 78 | { 79 | // If the same subscriber is already registered with the store, replace the existing 80 | // subscription with the new one. 81 | if let index = subscriptions.index(where: { $0.subscriber === subscriber }) { 82 | subscriptions.remove(at: index) 83 | } 84 | 85 | // Create a subscription for the new subscriber. 86 | let originalSubscription = Subscription() 87 | // Call the optional transformation closure. This allows callers to modify 88 | // the subscription, e.g. in order to subselect parts of the store's state. 89 | let transformedSubscription = transform?(originalSubscription) 90 | 91 | let subscriptionBox = SubscriptionBox( 92 | originalSubscription: originalSubscription, 93 | transformedSubscription: transformedSubscription, 94 | subscriber: subscriber 95 | ) 96 | 97 | subscriptions.append(subscriptionBox) 98 | 99 | if let state = self.state { 100 | originalSubscription.newValues(oldState: nil, newState: state) 101 | } 102 | } 103 | 104 | open func unsubscribe(_ subscriber: AnyStoreSubscriber) { 105 | if let index = subscriptions.index(where: { return $0.subscriber === subscriber }) { 106 | subscriptions.remove(at: index) 107 | } 108 | } 109 | 110 | // swiftlint:disable:next identifier_name 111 | open func _defaultDispatch(action: Action) { 112 | guard !isDispatching else { 113 | raiseFatalError( 114 | "ReSwift:ConcurrentMutationError- Action has been dispatched while" + 115 | " a previous action is action is being processed. A reducer" + 116 | " is dispatching an action, or ReSwift is used in a concurrent context" + 117 | " (e.g. from multiple threads)." 118 | ) 119 | } 120 | 121 | isDispatching = true 122 | let newState = reducer(action, state) 123 | isDispatching = false 124 | 125 | state = newState 126 | } 127 | 128 | open func dispatch(_ action: Action) { 129 | dispatchFunction(action) 130 | } 131 | 132 | open func dispatch(_ actionCreatorProvider: @escaping ActionCreator) { 133 | if let action = actionCreatorProvider(state, self) { 134 | dispatch(action) 135 | } 136 | } 137 | 138 | open func dispatch(_ asyncActionCreatorProvider: @escaping AsyncActionCreator) { 139 | dispatch(asyncActionCreatorProvider, callback: nil) 140 | } 141 | 142 | open func dispatch(_ actionCreatorProvider: @escaping AsyncActionCreator, 143 | callback: DispatchCallback?) { 144 | actionCreatorProvider(state, self) { actionProvider in 145 | let action = actionProvider(self.state, self) 146 | 147 | if let action = action { 148 | self.dispatch(action) 149 | callback?(self.state) 150 | } 151 | } 152 | } 153 | 154 | public typealias DispatchCallback = (State) -> Void 155 | 156 | public typealias ActionCreator = (_ state: State, _ store: Store) -> Action? 157 | 158 | public typealias AsyncActionCreator = ( 159 | _ state: State, 160 | _ store: Store, 161 | _ actionCreatorCallback: @escaping ((ActionCreator) -> Void) 162 | ) -> Void 163 | } 164 | 165 | // MARK: Skip Repeats for Equatable States 166 | 167 | extension Store where State: Equatable { 168 | open func subscribe(_ subscriber: S) 169 | where S.StoreSubscriberStateType == State { 170 | _ = subscribe(subscriber, transform: { $0.skipRepeats() }) 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/StoreSubscriber.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoreSubscriber.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 12/14/15. 6 | // Copyright © 2015 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol AnyStoreSubscriber: class { 12 | // swiftlint:disable:next identifier_name 13 | func _newState(state: Any) 14 | } 15 | 16 | public protocol StoreSubscriber: AnyStoreSubscriber { 17 | associatedtype StoreSubscriberStateType 18 | 19 | func newState(state: StoreSubscriberStateType) 20 | } 21 | 22 | extension StoreSubscriber { 23 | // swiftlint:disable:next identifier_name 24 | public func _newState(state: Any) { 25 | if let typedState = state as? StoreSubscriberStateType { 26 | newState(state: typedState) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/StoreType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoreType.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 11/28/15. 6 | // Copyright © 2015 DigiTales. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Defines the interface of Stores in ReSwift. `Store` is the default implementation of this 13 | interface. Applications have a single store that stores the entire application state. 14 | Stores receive actions and use reducers combined with these actions, to calculate state changes. 15 | Upon every state update a store informs all of its subscribers. 16 | */ 17 | public protocol StoreType: DispatchingStoreType { 18 | 19 | associatedtype State: StateType 20 | 21 | /// Initializes the store with a reducer, an initial state and a list of middleware. 22 | /// Middleware is applied in the order in which it is passed into this constructor. 23 | init(reducer: @escaping Reducer, state: State?, middleware: [Middleware]) 24 | 25 | /// The current state stored in the store. 26 | var state: State! { get } 27 | 28 | /** 29 | The main dispatch function that is used by all convenience `dispatch` methods. 30 | This dispatch function can be extended by providing middlewares. 31 | */ 32 | var dispatchFunction: DispatchFunction! { get } 33 | 34 | /** 35 | Subscribes the provided subscriber to this store. 36 | Subscribers will receive a call to `newState` whenever the 37 | state in this store changes. 38 | 39 | - parameter subscriber: Subscriber that will receive store updates 40 | */ 41 | func subscribe(_ subscriber: S) where S.StoreSubscriberStateType == State 42 | 43 | /** 44 | Subscribes the provided subscriber to this store. 45 | Subscribers will receive a call to `newState` whenever the 46 | state in this store changes and the subscription decides to forward 47 | state update. 48 | 49 | - parameter subscriber: Subscriber that will receive store updates 50 | - parameter transform: A closure that receives a simple subscription and can return a 51 | transformed subscription. Subscriptions can be transformed to only select a subset of the 52 | state, or to skip certain state updates. 53 | */ 54 | func subscribe( 55 | _ subscriber: S, transform: ((Subscription) -> Subscription)? 56 | ) where S.StoreSubscriberStateType == SelectedState 57 | 58 | /** 59 | Unsubscribes the provided subscriber. The subscriber will no longer 60 | receive state updates from this store. 61 | 62 | - parameter subscriber: Subscriber that will be unsubscribed 63 | */ 64 | func unsubscribe(_ subscriber: AnyStoreSubscriber) 65 | 66 | /** 67 | Dispatches an action creator to the store. Action creators are functions that generate 68 | actions. They are called by the store and receive the current state of the application 69 | and a reference to the store as their input. 70 | 71 | Based on that input the action creator can either return an action or not. Alternatively 72 | the action creator can also perform an asynchronous operation and dispatch a new action 73 | at the end of it. 74 | 75 | Example of an action creator: 76 | 77 | ``` 78 | func deleteNote(noteID: Int) -> ActionCreator { 79 | return { state, store in 80 | // only delete note if editing is enabled 81 | if (state.editingEnabled == true) { 82 | return NoteDataAction.DeleteNote(noteID) 83 | } else { 84 | return nil 85 | } 86 | } 87 | } 88 | ``` 89 | 90 | This action creator can then be dispatched as following: 91 | 92 | ``` 93 | store.dispatch( noteActionCreatore.deleteNote(3) ) 94 | ``` 95 | 96 | - returns: By default returns the dispatched action, but middlewares can change the 97 | return type, e.g. to return promises 98 | */ 99 | func dispatch(_ actionCreator: ActionCreator) 100 | 101 | /** 102 | Dispatches an async action creator to the store. An async action creator generates an 103 | action creator asynchronously. 104 | */ 105 | func dispatch(_ asyncActionCreator: AsyncActionCreator) 106 | 107 | /** 108 | Dispatches an async action creator to the store. An async action creator generates an 109 | action creator asynchronously. Use this method if you want to wait for the state change 110 | triggered by the asynchronously generated action creator. 111 | 112 | This overloaded version of `dispatch` calls the provided `callback` as soon as the 113 | asynchronoously dispatched action has caused a new state calculation. 114 | 115 | - Note: If the ActionCreator does not dispatch an action, the callback block will never 116 | be called 117 | */ 118 | func dispatch(_ asyncActionCreator: AsyncActionCreator, callback: DispatchCallback?) 119 | 120 | /** 121 | An optional callback that can be passed to the `dispatch` method. 122 | This callback will be called when the dispatched action triggers a new state calculation. 123 | This is useful when you need to wait on a state change, triggered by an action (e.g. wait on 124 | a successful login). However, you should try to use this callback very seldom as it 125 | deviates slighlty from the unidirectional data flow principal. 126 | */ 127 | associatedtype DispatchCallback = (State) -> Void 128 | 129 | /** 130 | An ActionCreator is a function that, based on the received state argument, might or might not 131 | create an action. 132 | 133 | Example: 134 | 135 | ``` 136 | func deleteNote(noteID: Int) -> ActionCreator { 137 | return { state, store in 138 | // only delete note if editing is enabled 139 | if (state.editingEnabled == true) { 140 | return NoteDataAction.DeleteNote(noteID) 141 | } else { 142 | return nil 143 | } 144 | } 145 | } 146 | ``` 147 | 148 | */ 149 | associatedtype ActionCreator = (_ state: State, _ store: StoreType) -> Action? 150 | 151 | /// AsyncActionCreators allow the developer to wait for the completion of an async action. 152 | associatedtype AsyncActionCreator = 153 | (_ state: State, _ store: StoreType, 154 | _ actionCreatorCallback: (ActionCreator) -> Void) -> Void 155 | } 156 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/CoreTypes/Subscription.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SubscriberWrapper.swift 3 | // ReSwift 4 | // 5 | // Created by Virgilio Favero Neto on 4/02/2016. 6 | // Copyright © 2016 Benjamin Encz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// A box around subscriptions and subscribers. 12 | /// 13 | /// Acts as a type-erasing wrapper around a subscription and its transformed subscription. 14 | /// The transformed subscription has a type argument that matches the selected substate of the 15 | /// subscriber; however that type cannot be exposed to the store. 16 | /// 17 | /// The box subscribes either to the original subscription, or if available to the transformed 18 | /// subscription and passes any values that come through this subscriptions to the subscriber. 19 | class SubscriptionBox { 20 | 21 | private let originalSubscription: Subscription 22 | weak var subscriber: AnyStoreSubscriber? 23 | 24 | init( 25 | originalSubscription: Subscription, 26 | transformedSubscription: Subscription?, 27 | subscriber: AnyStoreSubscriber 28 | ) { 29 | self.originalSubscription = originalSubscription 30 | self.subscriber = subscriber 31 | 32 | // If we received a transformed subscription, we subscribe to that subscription 33 | // and forward all new values to the subscriber. 34 | if let transformedSubscription = transformedSubscription { 35 | transformedSubscription.observe { _, newState in 36 | self.subscriber?._newState(state: newState as Any) 37 | } 38 | // If we haven't received a transformed subscription, we forward all values 39 | // from the original subscription. 40 | } else { 41 | originalSubscription.observe { _, newState in 42 | self.subscriber?._newState(state: newState as Any) 43 | } 44 | } 45 | } 46 | 47 | func newValues(oldState: State, newState: State) { 48 | // We pass all new values through the original subscription, which accepts 49 | // values of type ``. If present, transformed subscriptions will 50 | // receive this update and transform it before passing it on to the subscriber. 51 | self.originalSubscription.newValues(oldState: oldState, newState: newState) 52 | } 53 | } 54 | 55 | /// Represents a subscription of a subscriber to the store. The subscription determines which new 56 | /// values from the store are forwarded to the subscriber, and how they are transformed. 57 | /// The subscription acts as a very-light weight signal/observable that you might know from 58 | /// reactive programming libraries. 59 | public class Subscription { 60 | 61 | private func _select( 62 | _ selector: @escaping (State) -> Substate 63 | ) -> Subscription 64 | { 65 | return Subscription { sink in 66 | self.observe { oldState, newState in 67 | sink(oldState.map(selector) ?? nil, newState.map(selector) ?? nil) 68 | } 69 | } 70 | } 71 | 72 | // MARK: Public Interface 73 | 74 | /// Provides a subscription that selects a substate of the state of the original subscription. 75 | /// - parameter selector: A closure that maps a state to a selected substate 76 | public func select( 77 | _ selector: @escaping (State) -> Substate 78 | ) -> Subscription 79 | { 80 | return self._select(selector) 81 | } 82 | 83 | /// Provides a subscription that selects a substate of the state of the original subscription. 84 | /// If the selected substate is `Equatable` repeated state updates will be skipped. 85 | /// - parameter selector: A closure that maps a state to a selected substate 86 | public func select( 87 | _ selector: @escaping (State) -> Substate 88 | ) -> Subscription 89 | { 90 | return self._select(selector).skipRepeats() 91 | } 92 | 93 | /// Provides a subscription that skips certain state updates of the original subscription. 94 | /// - parameter isRepeat: A closure that determines whether a given state update is a repeat and 95 | /// thus should be skipped and not forwarded to subscribers. 96 | public func skipRepeats(_ isRepeat: @escaping (State, State) -> Bool) -> Subscription { 97 | return Subscription { sink in 98 | self.observe { oldState, newState in 99 | switch (oldState, newState) { 100 | case let (old?, new?): 101 | if !isRepeat(old, new) { 102 | sink(oldState, newState) 103 | } else { 104 | return 105 | } 106 | default: 107 | sink(oldState, newState) 108 | } 109 | } 110 | } 111 | } 112 | 113 | // MARK: Internals 114 | 115 | var observer: ((State?, State?) -> Void)? 116 | 117 | init() {} 118 | 119 | /// Initializes a subscription with a sink closure. The closure provides a way to send 120 | /// new values over this subscription. 121 | private init(sink: @escaping (@escaping (State?, State?) -> Void) -> Void) { 122 | // Provide the caller with a closure that will forward all values 123 | // to observers of this subscription. 124 | sink { old, new in 125 | self.newValues(oldState: old, newState: new) 126 | } 127 | } 128 | 129 | /// Sends new values over this subscription. Observers will be notified of these new values. 130 | func newValues(oldState: State?, newState: State?) { 131 | self.observer?(oldState, newState) 132 | } 133 | 134 | /// A caller can observe new values of this subscription through the provided closure. 135 | /// - Note: subscriptions only support a single observer. 136 | fileprivate func observe(observer: @escaping (State?, State?) -> Void) { 137 | self.observer = observer 138 | } 139 | } 140 | 141 | extension Subscription where State: Equatable { 142 | public func skipRepeats() -> Subscription{ 143 | return self.skipRepeats(==) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/Utils/Assertions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Assertions 3 | // Copyright © 2015 mohamede1945. All rights reserved. 4 | // https://github.com/mohamede1945/AssertionsTestingExample 5 | // 6 | 7 | import Foundation 8 | 9 | /// drop-in fatalError replacement for testing 10 | 11 | /** 12 | Swift.fatalError wrapper for catching in tests 13 | 14 | - parameter message: Message to be wrapped 15 | - parameter file: Calling file 16 | - parameter line: Calling line 17 | */ 18 | internal func raiseFatalError(_ message: @autoclosure () -> String = "", 19 | file: StaticString = #file, line: UInt = #line) -> Never { 20 | Assertions.fatalErrorClosure(message(), file, line) 21 | repeat { 22 | RunLoop.current.run() 23 | } while (true) 24 | } 25 | 26 | /// Stores custom assertions closures, by default it points to Swift functions. But test target can 27 | /// override them. 28 | internal class Assertions { 29 | internal static var fatalErrorClosure = swiftFatalErrorClosure 30 | internal static let swiftFatalErrorClosure: (String, StaticString, UInt) -> Void 31 | = { Swift.fatalError($0, file: $1, line: $2) } 32 | } 33 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/Utils/Coding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 11/27/15. 6 | // Copyright © 2015 DigiTales. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol Coding { 12 | init?(dictionary: [String: AnyObject]) 13 | var dictionaryRepresentation: [String: AnyObject] { get } 14 | } 15 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/ReSwift/ReSwift/Utils/TypeHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TypeHelper.swift 3 | // ReSwift 4 | // 5 | // Created by Benjamin Encz on 11/27/15. 6 | // Copyright © 2015 DigiTales. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | Method is only used internally in ReSwift to cast the generic `StateType` to a specific 13 | type expected by reducers / store subscribers. 14 | 15 | - parameter action: An action that will be passed to `handleAction`. 16 | - parameter state: A generic state type that will be casted to `SpecificStateType`. 17 | - parameter function: The `handleAction` method. 18 | - returns: A `StateType` from `handleAction` or the original `StateType` if it cannot be 19 | casted to `SpecificStateType`. 20 | */ 21 | @discardableResult 22 | func withSpecificTypes( 23 | _ action: Action, 24 | state genericStateType: StateType?, 25 | function: (_ action: Action, _ state: SpecificStateType?) -> SpecificStateType 26 | ) -> StateType { 27 | guard let genericStateType = genericStateType else { 28 | return function(action, nil) as! StateType 29 | } 30 | 31 | guard let specificStateType = genericStateType as? SpecificStateType else { 32 | return genericStateType 33 | } 34 | 35 | return function(action, specificStateType) as! StateType 36 | } 37 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## ReSwift 5 | 6 | The MIT License (MIT) 7 | Copyright (c) 2016 ReSwift Contributors 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | Generated by CocoaPods - https://cocoapods.org 15 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | Copyright (c) 2016 ReSwift Contributors 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | License 26 | MIT 27 | Title 28 | ReSwift 29 | Type 30 | PSGroupSpecifier 31 | 32 | 33 | FooterText 34 | Generated by CocoaPods - https://cocoapods.org 35 | Title 36 | 37 | Type 38 | PSGroupSpecifier 39 | 40 | 41 | StringsTable 42 | Acknowledgements 43 | Title 44 | Acknowledgements 45 | 46 | 47 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ReduxPaperScissors : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ReduxPaperScissors 5 | @end 6 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 63 | 64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 65 | code_sign_cmd="$code_sign_cmd &" 66 | fi 67 | echo "$code_sign_cmd" 68 | eval "$code_sign_cmd" 69 | fi 70 | } 71 | 72 | # Strip invalid architectures 73 | strip_invalid_archs() { 74 | binary="$1" 75 | # Get architectures for current file 76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 77 | stripped="" 78 | for arch in $archs; do 79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 80 | # Strip non-valid architectures in-place 81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 82 | stripped="$stripped $arch" 83 | fi 84 | done 85 | if [[ "$stripped" ]]; then 86 | echo "Stripped $binary of architectures:$stripped" 87 | fi 88 | } 89 | 90 | 91 | if [[ "$CONFIGURATION" == "Debug" ]]; then 92 | install_framework "$BUILT_PRODUCTS_DIR/ReSwift/ReSwift.framework" 93 | fi 94 | if [[ "$CONFIGURATION" == "Release" ]]; then 95 | install_framework "$BUILT_PRODUCTS_DIR/ReSwift/ReSwift.framework" 96 | fi 97 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 98 | wait 99 | fi 100 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | case "${TARGETED_DEVICE_FAMILY}" in 12 | 1,2) 13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 14 | ;; 15 | 1) 16 | TARGET_DEVICE_ARGS="--target-device iphone" 17 | ;; 18 | 2) 19 | TARGET_DEVICE_ARGS="--target-device ipad" 20 | ;; 21 | 3) 22 | TARGET_DEVICE_ARGS="--target-device tv" 23 | ;; 24 | *) 25 | TARGET_DEVICE_ARGS="--target-device mac" 26 | ;; 27 | esac 28 | 29 | install_resource() 30 | { 31 | if [[ "$1" = /* ]] ; then 32 | RESOURCE_PATH="$1" 33 | else 34 | RESOURCE_PATH="${PODS_ROOT}/$1" 35 | fi 36 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 37 | cat << EOM 38 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 39 | EOM 40 | exit 1 41 | fi 42 | case $RESOURCE_PATH in 43 | *.storyboard) 44 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 45 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 46 | ;; 47 | *.xib) 48 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 49 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 50 | ;; 51 | *.framework) 52 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 53 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 54 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 55 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 56 | ;; 57 | *.xcdatamodel) 58 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" 59 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 60 | ;; 61 | *.xcdatamodeld) 62 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" 63 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 64 | ;; 65 | *.xcmappingmodel) 66 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" 67 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 68 | ;; 69 | *.xcassets) 70 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 71 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 72 | ;; 73 | *) 74 | echo "$RESOURCE_PATH" 75 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 76 | ;; 77 | esac 78 | } 79 | 80 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 82 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 83 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 85 | fi 86 | rm -f "$RESOURCES_TO_COPY" 87 | 88 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 89 | then 90 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 91 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 92 | while read line; do 93 | if [[ $line != "${PODS_ROOT}*" ]]; then 94 | XCASSET_FILES+=("$line") 95 | fi 96 | done <<<"$OTHER_XCASSETS" 97 | 98 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | fi 100 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ReduxPaperScissorsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ReduxPaperScissorsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ReSwift" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReSwift/ReSwift.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "ReSwift" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ReduxPaperScissors { 2 | umbrella header "Pods-ReduxPaperScissors-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ReSwift" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReSwift/ReSwift.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "ReSwift" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_ROOT = ${SRCROOT}/Pods 11 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ReduxPaperScissorsTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ReduxPaperScissorsTests 5 | @end 6 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 63 | 64 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 65 | code_sign_cmd="$code_sign_cmd &" 66 | fi 67 | echo "$code_sign_cmd" 68 | eval "$code_sign_cmd" 69 | fi 70 | } 71 | 72 | # Strip invalid architectures 73 | strip_invalid_archs() { 74 | binary="$1" 75 | # Get architectures for current file 76 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 77 | stripped="" 78 | for arch in $archs; do 79 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 80 | # Strip non-valid architectures in-place 81 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 82 | stripped="$stripped $arch" 83 | fi 84 | done 85 | if [[ "$stripped" ]]; then 86 | echo "Stripped $binary of architectures:$stripped" 87 | fi 88 | } 89 | 90 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 91 | wait 92 | fi 93 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | case "${TARGETED_DEVICE_FAMILY}" in 12 | 1,2) 13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 14 | ;; 15 | 1) 16 | TARGET_DEVICE_ARGS="--target-device iphone" 17 | ;; 18 | 2) 19 | TARGET_DEVICE_ARGS="--target-device ipad" 20 | ;; 21 | 3) 22 | TARGET_DEVICE_ARGS="--target-device tv" 23 | ;; 24 | *) 25 | TARGET_DEVICE_ARGS="--target-device mac" 26 | ;; 27 | esac 28 | 29 | install_resource() 30 | { 31 | if [[ "$1" = /* ]] ; then 32 | RESOURCE_PATH="$1" 33 | else 34 | RESOURCE_PATH="${PODS_ROOT}/$1" 35 | fi 36 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 37 | cat << EOM 38 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 39 | EOM 40 | exit 1 41 | fi 42 | case $RESOURCE_PATH in 43 | *.storyboard) 44 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 45 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 46 | ;; 47 | *.xib) 48 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 49 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 50 | ;; 51 | *.framework) 52 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 53 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 54 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 55 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 56 | ;; 57 | *.xcdatamodel) 58 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" 59 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 60 | ;; 61 | *.xcdatamodeld) 62 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" 63 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 64 | ;; 65 | *.xcmappingmodel) 66 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" 67 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 68 | ;; 69 | *.xcassets) 70 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 71 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 72 | ;; 73 | *) 74 | echo "$RESOURCE_PATH" 75 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 76 | ;; 77 | esac 78 | } 79 | 80 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 82 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 83 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 84 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 85 | fi 86 | rm -f "$RESOURCES_TO_COPY" 87 | 88 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 89 | then 90 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 91 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 92 | while read line; do 93 | if [[ $line != "${PODS_ROOT}*" ]]; then 94 | XCASSET_FILES+=("$line") 95 | fi 96 | done <<<"$OTHER_XCASSETS" 97 | 98 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | fi 100 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ReduxPaperScissorsTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ReduxPaperScissorsTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ReSwift" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReSwift/ReSwift.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT}/Pods 8 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ReduxPaperScissorsTests { 2 | umbrella header "Pods-ReduxPaperScissorsTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/ReSwift" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/ReSwift/ReSwift.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT}/Pods 8 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 4.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/ReSwift-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_ReSwift : NSObject 3 | @end 4 | @implementation PodsDummy_ReSwift 5 | @end 6 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/ReSwift-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/ReSwift-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double ReSwiftVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char ReSwiftVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/ReSwift.modulemap: -------------------------------------------------------------------------------- 1 | framework module ReSwift { 2 | umbrella header "ReSwift-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /ReduxPaperScissors/Pods/Target Support Files/ReSwift/ReSwift.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/ReSwift 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/ReSwift 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 60B76AC01F323BB300223F17 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76ABF1F323BB300223F17 /* AppDelegate.swift */; }; 11 | 60B76AC21F323BB300223F17 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76AC11F323BB300223F17 /* ViewController.swift */; }; 12 | 60B76AC51F323BB300223F17 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 60B76AC31F323BB300223F17 /* Main.storyboard */; }; 13 | 60B76AC71F323BB300223F17 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60B76AC61F323BB300223F17 /* Assets.xcassets */; }; 14 | 60B76ACA1F323BB300223F17 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 60B76AC81F323BB300223F17 /* LaunchScreen.storyboard */; }; 15 | 60B76AD51F323BB300223F17 /* ReduxPaperScissorsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76AD41F323BB300223F17 /* ReduxPaperScissorsTests.swift */; }; 16 | 60B76AE11F323F1700223F17 /* Actions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76AE01F323F1700223F17 /* Actions.swift */; }; 17 | 60B76AE31F32406500223F17 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76AE21F32406500223F17 /* State.swift */; }; 18 | 60B76AE51F3240AE00223F17 /* Reducers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60B76AE41F3240AE00223F17 /* Reducers.swift */; }; 19 | 6CD6E8D39316BE01A0601465 /* Pods_ReduxPaperScissorsTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C924EACECD97C6AA0E2352D7 /* Pods_ReduxPaperScissorsTests.framework */; }; 20 | FE373AF91A069A76C0935935 /* Pods_ReduxPaperScissors.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF521EF8D7BD11CD0D387AC0 /* Pods_ReduxPaperScissors.framework */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 60B76AD11F323BB300223F17 /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = 60B76AB41F323BB300223F17 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = 60B76ABB1F323BB300223F17; 29 | remoteInfo = ReduxPaperScissors; 30 | }; 31 | /* End PBXContainerItemProxy section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 08E002BF750C81AAC5610623 /* Pods-ReduxPaperScissors.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReduxPaperScissors.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.debug.xcconfig"; sourceTree = ""; }; 35 | 23C4C9129821865AD08D683F /* Pods-ReduxPaperScissorsTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReduxPaperScissorsTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.release.xcconfig"; sourceTree = ""; }; 36 | 388E721866687CEED9E4CB58 /* Pods-ReduxPaperScissors.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReduxPaperScissors.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors.release.xcconfig"; sourceTree = ""; }; 37 | 5F7B0C206178102412AAEDAA /* Pods-ReduxPaperScissorsTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReduxPaperScissorsTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests.debug.xcconfig"; sourceTree = ""; }; 38 | 60B76ABC1F323BB300223F17 /* ReduxPaperScissors.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReduxPaperScissors.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 60B76ABF1F323BB300223F17 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 60B76AC11F323BB300223F17 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 41 | 60B76AC41F323BB300223F17 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 60B76AC61F323BB300223F17 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 60B76AC91F323BB300223F17 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 60B76ACB1F323BB300223F17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 60B76AD01F323BB300223F17 /* ReduxPaperScissorsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReduxPaperScissorsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 60B76AD41F323BB300223F17 /* ReduxPaperScissorsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReduxPaperScissorsTests.swift; sourceTree = ""; }; 47 | 60B76AD61F323BB300223F17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 60B76AE01F323F1700223F17 /* Actions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Actions.swift; sourceTree = ""; }; 49 | 60B76AE21F32406500223F17 /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; 50 | 60B76AE41F3240AE00223F17 /* Reducers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reducers.swift; sourceTree = ""; }; 51 | C924EACECD97C6AA0E2352D7 /* Pods_ReduxPaperScissorsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReduxPaperScissorsTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | CF521EF8D7BD11CD0D387AC0 /* Pods_ReduxPaperScissors.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ReduxPaperScissors.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 60B76AB91F323BB300223F17 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | FE373AF91A069A76C0935935 /* Pods_ReduxPaperScissors.framework in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | 60B76ACD1F323BB300223F17 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 6CD6E8D39316BE01A0601465 /* Pods_ReduxPaperScissorsTests.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXFrameworksBuildPhase section */ 73 | 74 | /* Begin PBXGroup section */ 75 | 49AE684634A7A6A64D73FCFD /* Pods */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 08E002BF750C81AAC5610623 /* Pods-ReduxPaperScissors.debug.xcconfig */, 79 | 388E721866687CEED9E4CB58 /* Pods-ReduxPaperScissors.release.xcconfig */, 80 | 5F7B0C206178102412AAEDAA /* Pods-ReduxPaperScissorsTests.debug.xcconfig */, 81 | 23C4C9129821865AD08D683F /* Pods-ReduxPaperScissorsTests.release.xcconfig */, 82 | ); 83 | name = Pods; 84 | sourceTree = ""; 85 | }; 86 | 60B76AB31F323BB300223F17 = { 87 | isa = PBXGroup; 88 | children = ( 89 | 60B76ABE1F323BB300223F17 /* ReduxPaperScissors */, 90 | 60B76AD31F323BB300223F17 /* ReduxPaperScissorsTests */, 91 | 60B76ABD1F323BB300223F17 /* Products */, 92 | 49AE684634A7A6A64D73FCFD /* Pods */, 93 | B0C837E6993F9A86C9116FF3 /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 60B76ABD1F323BB300223F17 /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 60B76ABC1F323BB300223F17 /* ReduxPaperScissors.app */, 101 | 60B76AD01F323BB300223F17 /* ReduxPaperScissorsTests.xctest */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | 60B76ABE1F323BB300223F17 /* ReduxPaperScissors */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 60B76ACB1F323BB300223F17 /* Info.plist */, 110 | 60B76AC81F323BB300223F17 /* LaunchScreen.storyboard */, 111 | 60B76ABF1F323BB300223F17 /* AppDelegate.swift */, 112 | 60B76ADF1F323EF600223F17 /* Redux */, 113 | 60B76AC11F323BB300223F17 /* ViewController.swift */, 114 | 60B76AC31F323BB300223F17 /* Main.storyboard */, 115 | 60B76AC61F323BB300223F17 /* Assets.xcassets */, 116 | ); 117 | path = ReduxPaperScissors; 118 | sourceTree = ""; 119 | }; 120 | 60B76AD31F323BB300223F17 /* ReduxPaperScissorsTests */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 60B76AD41F323BB300223F17 /* ReduxPaperScissorsTests.swift */, 124 | 60B76AD61F323BB300223F17 /* Info.plist */, 125 | ); 126 | path = ReduxPaperScissorsTests; 127 | sourceTree = ""; 128 | }; 129 | 60B76ADF1F323EF600223F17 /* Redux */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 60B76AE01F323F1700223F17 /* Actions.swift */, 133 | 60B76AE21F32406500223F17 /* State.swift */, 134 | 60B76AE41F3240AE00223F17 /* Reducers.swift */, 135 | ); 136 | name = Redux; 137 | sourceTree = ""; 138 | }; 139 | B0C837E6993F9A86C9116FF3 /* Frameworks */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | CF521EF8D7BD11CD0D387AC0 /* Pods_ReduxPaperScissors.framework */, 143 | C924EACECD97C6AA0E2352D7 /* Pods_ReduxPaperScissorsTests.framework */, 144 | ); 145 | name = Frameworks; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 60B76ABB1F323BB300223F17 /* ReduxPaperScissors */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 60B76AD91F323BB300223F17 /* Build configuration list for PBXNativeTarget "ReduxPaperScissors" */; 154 | buildPhases = ( 155 | 00B32F620593A0D0464C932F /* [CP] Check Pods Manifest.lock */, 156 | 60B76AB81F323BB300223F17 /* Sources */, 157 | 60B76AB91F323BB300223F17 /* Frameworks */, 158 | 60B76ABA1F323BB300223F17 /* Resources */, 159 | B58A58B3BB8F4E1D2AEBFE67 /* [CP] Embed Pods Frameworks */, 160 | F75517866B8BA56289D63C72 /* [CP] Copy Pods Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | ); 166 | name = ReduxPaperScissors; 167 | productName = ReduxPaperScissors; 168 | productReference = 60B76ABC1F323BB300223F17 /* ReduxPaperScissors.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | 60B76ACF1F323BB300223F17 /* ReduxPaperScissorsTests */ = { 172 | isa = PBXNativeTarget; 173 | buildConfigurationList = 60B76ADC1F323BB300223F17 /* Build configuration list for PBXNativeTarget "ReduxPaperScissorsTests" */; 174 | buildPhases = ( 175 | C89934EF49EC99B9E1856BA0 /* [CP] Check Pods Manifest.lock */, 176 | 60B76ACC1F323BB300223F17 /* Sources */, 177 | 60B76ACD1F323BB300223F17 /* Frameworks */, 178 | 60B76ACE1F323BB300223F17 /* Resources */, 179 | 06E37D00B190B70A1ADD6E58 /* [CP] Embed Pods Frameworks */, 180 | 60942913AAD157FCD9C01FBE /* [CP] Copy Pods Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | 60B76AD21F323BB300223F17 /* PBXTargetDependency */, 186 | ); 187 | name = ReduxPaperScissorsTests; 188 | productName = ReduxPaperScissorsTests; 189 | productReference = 60B76AD01F323BB300223F17 /* ReduxPaperScissorsTests.xctest */; 190 | productType = "com.apple.product-type.bundle.unit-test"; 191 | }; 192 | /* End PBXNativeTarget section */ 193 | 194 | /* Begin PBXProject section */ 195 | 60B76AB41F323BB300223F17 /* Project object */ = { 196 | isa = PBXProject; 197 | attributes = { 198 | LastSwiftUpdateCheck = 0830; 199 | LastUpgradeCheck = 0830; 200 | ORGANIZATIONNAME = "Julio Bertolacini Organization"; 201 | TargetAttributes = { 202 | 60B76ABB1F323BB300223F17 = { 203 | CreatedOnToolsVersion = 8.3.2; 204 | DevelopmentTeam = X68268NT2J; 205 | ProvisioningStyle = Automatic; 206 | }; 207 | 60B76ACF1F323BB300223F17 = { 208 | CreatedOnToolsVersion = 8.3.2; 209 | DevelopmentTeam = X68268NT2J; 210 | ProvisioningStyle = Automatic; 211 | TestTargetID = 60B76ABB1F323BB300223F17; 212 | }; 213 | }; 214 | }; 215 | buildConfigurationList = 60B76AB71F323BB300223F17 /* Build configuration list for PBXProject "ReduxPaperScissors" */; 216 | compatibilityVersion = "Xcode 3.2"; 217 | developmentRegion = English; 218 | hasScannedForEncodings = 0; 219 | knownRegions = ( 220 | en, 221 | Base, 222 | ); 223 | mainGroup = 60B76AB31F323BB300223F17; 224 | productRefGroup = 60B76ABD1F323BB300223F17 /* Products */; 225 | projectDirPath = ""; 226 | projectRoot = ""; 227 | targets = ( 228 | 60B76ABB1F323BB300223F17 /* ReduxPaperScissors */, 229 | 60B76ACF1F323BB300223F17 /* ReduxPaperScissorsTests */, 230 | ); 231 | }; 232 | /* End PBXProject section */ 233 | 234 | /* Begin PBXResourcesBuildPhase section */ 235 | 60B76ABA1F323BB300223F17 /* Resources */ = { 236 | isa = PBXResourcesBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | 60B76ACA1F323BB300223F17 /* LaunchScreen.storyboard in Resources */, 240 | 60B76AC71F323BB300223F17 /* Assets.xcassets in Resources */, 241 | 60B76AC51F323BB300223F17 /* Main.storyboard in Resources */, 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | 60B76ACE1F323BB300223F17 /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | /* End PBXResourcesBuildPhase section */ 253 | 254 | /* Begin PBXShellScriptBuildPhase section */ 255 | 00B32F620593A0D0464C932F /* [CP] Check Pods Manifest.lock */ = { 256 | isa = PBXShellScriptBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | inputPaths = ( 261 | ); 262 | name = "[CP] Check Pods Manifest.lock"; 263 | outputPaths = ( 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | shellPath = /bin/sh; 267 | shellScript = "diff \"${PODS_ROOT}/../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"; 268 | showEnvVarsInLog = 0; 269 | }; 270 | 06E37D00B190B70A1ADD6E58 /* [CP] Embed Pods Frameworks */ = { 271 | isa = PBXShellScriptBuildPhase; 272 | buildActionMask = 2147483647; 273 | files = ( 274 | ); 275 | inputPaths = ( 276 | ); 277 | name = "[CP] Embed Pods Frameworks"; 278 | outputPaths = ( 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | shellPath = /bin/sh; 282 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-frameworks.sh\"\n"; 283 | showEnvVarsInLog = 0; 284 | }; 285 | 60942913AAD157FCD9C01FBE /* [CP] Copy Pods Resources */ = { 286 | isa = PBXShellScriptBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | ); 290 | inputPaths = ( 291 | ); 292 | name = "[CP] Copy Pods Resources"; 293 | outputPaths = ( 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | shellPath = /bin/sh; 297 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReduxPaperScissorsTests/Pods-ReduxPaperScissorsTests-resources.sh\"\n"; 298 | showEnvVarsInLog = 0; 299 | }; 300 | B58A58B3BB8F4E1D2AEBFE67 /* [CP] Embed Pods Frameworks */ = { 301 | isa = PBXShellScriptBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | ); 305 | inputPaths = ( 306 | ); 307 | name = "[CP] Embed Pods Frameworks"; 308 | outputPaths = ( 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | shellPath = /bin/sh; 312 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-frameworks.sh\"\n"; 313 | showEnvVarsInLog = 0; 314 | }; 315 | C89934EF49EC99B9E1856BA0 /* [CP] Check Pods Manifest.lock */ = { 316 | isa = PBXShellScriptBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | ); 320 | inputPaths = ( 321 | ); 322 | name = "[CP] Check Pods Manifest.lock"; 323 | outputPaths = ( 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | shellPath = /bin/sh; 327 | shellScript = "diff \"${PODS_ROOT}/../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"; 328 | showEnvVarsInLog = 0; 329 | }; 330 | F75517866B8BA56289D63C72 /* [CP] Copy Pods Resources */ = { 331 | isa = PBXShellScriptBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | ); 335 | inputPaths = ( 336 | ); 337 | name = "[CP] Copy Pods Resources"; 338 | outputPaths = ( 339 | ); 340 | runOnlyForDeploymentPostprocessing = 0; 341 | shellPath = /bin/sh; 342 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReduxPaperScissors/Pods-ReduxPaperScissors-resources.sh\"\n"; 343 | showEnvVarsInLog = 0; 344 | }; 345 | /* End PBXShellScriptBuildPhase section */ 346 | 347 | /* Begin PBXSourcesBuildPhase section */ 348 | 60B76AB81F323BB300223F17 /* Sources */ = { 349 | isa = PBXSourcesBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | 60B76AE11F323F1700223F17 /* Actions.swift in Sources */, 353 | 60B76AE51F3240AE00223F17 /* Reducers.swift in Sources */, 354 | 60B76AC21F323BB300223F17 /* ViewController.swift in Sources */, 355 | 60B76AC01F323BB300223F17 /* AppDelegate.swift in Sources */, 356 | 60B76AE31F32406500223F17 /* State.swift in Sources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | 60B76ACC1F323BB300223F17 /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 60B76AD51F323BB300223F17 /* ReduxPaperScissorsTests.swift in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | /* End PBXSourcesBuildPhase section */ 369 | 370 | /* Begin PBXTargetDependency section */ 371 | 60B76AD21F323BB300223F17 /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = 60B76ABB1F323BB300223F17 /* ReduxPaperScissors */; 374 | targetProxy = 60B76AD11F323BB300223F17 /* PBXContainerItemProxy */; 375 | }; 376 | /* End PBXTargetDependency section */ 377 | 378 | /* Begin PBXVariantGroup section */ 379 | 60B76AC31F323BB300223F17 /* Main.storyboard */ = { 380 | isa = PBXVariantGroup; 381 | children = ( 382 | 60B76AC41F323BB300223F17 /* Base */, 383 | ); 384 | name = Main.storyboard; 385 | sourceTree = ""; 386 | }; 387 | 60B76AC81F323BB300223F17 /* LaunchScreen.storyboard */ = { 388 | isa = PBXVariantGroup; 389 | children = ( 390 | 60B76AC91F323BB300223F17 /* Base */, 391 | ); 392 | name = LaunchScreen.storyboard; 393 | sourceTree = ""; 394 | }; 395 | /* End PBXVariantGroup section */ 396 | 397 | /* Begin XCBuildConfiguration section */ 398 | 60B76AD71F323BB300223F17 /* Debug */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | ALWAYS_SEARCH_USER_PATHS = NO; 402 | CLANG_ANALYZER_NONNULL = YES; 403 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 404 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 405 | CLANG_CXX_LIBRARY = "libc++"; 406 | CLANG_ENABLE_MODULES = YES; 407 | CLANG_ENABLE_OBJC_ARC = YES; 408 | CLANG_WARN_BOOL_CONVERSION = YES; 409 | CLANG_WARN_CONSTANT_CONVERSION = YES; 410 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 411 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 412 | CLANG_WARN_EMPTY_BODY = YES; 413 | CLANG_WARN_ENUM_CONVERSION = YES; 414 | CLANG_WARN_INFINITE_RECURSION = YES; 415 | CLANG_WARN_INT_CONVERSION = YES; 416 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 417 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 418 | CLANG_WARN_UNREACHABLE_CODE = YES; 419 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 420 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 421 | COPY_PHASE_STRIP = NO; 422 | DEBUG_INFORMATION_FORMAT = dwarf; 423 | ENABLE_STRICT_OBJC_MSGSEND = YES; 424 | ENABLE_TESTABILITY = YES; 425 | GCC_C_LANGUAGE_STANDARD = gnu99; 426 | GCC_DYNAMIC_NO_PIC = NO; 427 | GCC_NO_COMMON_BLOCKS = YES; 428 | GCC_OPTIMIZATION_LEVEL = 0; 429 | GCC_PREPROCESSOR_DEFINITIONS = ( 430 | "DEBUG=1", 431 | "$(inherited)", 432 | ); 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 440 | MTL_ENABLE_DEBUG_INFO = YES; 441 | ONLY_ACTIVE_ARCH = YES; 442 | SDKROOT = iphoneos; 443 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 444 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 445 | }; 446 | name = Debug; 447 | }; 448 | 60B76AD81F323BB300223F17 /* Release */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | ALWAYS_SEARCH_USER_PATHS = NO; 452 | CLANG_ANALYZER_NONNULL = YES; 453 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 454 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 455 | CLANG_CXX_LIBRARY = "libc++"; 456 | CLANG_ENABLE_MODULES = YES; 457 | CLANG_ENABLE_OBJC_ARC = YES; 458 | CLANG_WARN_BOOL_CONVERSION = YES; 459 | CLANG_WARN_CONSTANT_CONVERSION = YES; 460 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 461 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 462 | CLANG_WARN_EMPTY_BODY = YES; 463 | CLANG_WARN_ENUM_CONVERSION = YES; 464 | CLANG_WARN_INFINITE_RECURSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 468 | CLANG_WARN_UNREACHABLE_CODE = YES; 469 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 470 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 471 | COPY_PHASE_STRIP = NO; 472 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 473 | ENABLE_NS_ASSERTIONS = NO; 474 | ENABLE_STRICT_OBJC_MSGSEND = YES; 475 | GCC_C_LANGUAGE_STANDARD = gnu99; 476 | GCC_NO_COMMON_BLOCKS = YES; 477 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 478 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 479 | GCC_WARN_UNDECLARED_SELECTOR = YES; 480 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 481 | GCC_WARN_UNUSED_FUNCTION = YES; 482 | GCC_WARN_UNUSED_VARIABLE = YES; 483 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 484 | MTL_ENABLE_DEBUG_INFO = NO; 485 | SDKROOT = iphoneos; 486 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 487 | VALIDATE_PRODUCT = YES; 488 | }; 489 | name = Release; 490 | }; 491 | 60B76ADA1F323BB300223F17 /* Debug */ = { 492 | isa = XCBuildConfiguration; 493 | baseConfigurationReference = 08E002BF750C81AAC5610623 /* Pods-ReduxPaperScissors.debug.xcconfig */; 494 | buildSettings = { 495 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 496 | DEVELOPMENT_TEAM = X68268NT2J; 497 | INFOPLIST_FILE = ReduxPaperScissors/Info.plist; 498 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 499 | PRODUCT_BUNDLE_IDENTIFIER = com.juliobertolacini.ReduxPaperScissors; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | SWIFT_VERSION = 3.0; 502 | }; 503 | name = Debug; 504 | }; 505 | 60B76ADB1F323BB300223F17 /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | baseConfigurationReference = 388E721866687CEED9E4CB58 /* Pods-ReduxPaperScissors.release.xcconfig */; 508 | buildSettings = { 509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 510 | DEVELOPMENT_TEAM = X68268NT2J; 511 | INFOPLIST_FILE = ReduxPaperScissors/Info.plist; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = com.juliobertolacini.ReduxPaperScissors; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | SWIFT_VERSION = 3.0; 516 | }; 517 | name = Release; 518 | }; 519 | 60B76ADD1F323BB300223F17 /* Debug */ = { 520 | isa = XCBuildConfiguration; 521 | baseConfigurationReference = 5F7B0C206178102412AAEDAA /* Pods-ReduxPaperScissorsTests.debug.xcconfig */; 522 | buildSettings = { 523 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 524 | BUNDLE_LOADER = "$(TEST_HOST)"; 525 | DEVELOPMENT_TEAM = X68268NT2J; 526 | INFOPLIST_FILE = ReduxPaperScissorsTests/Info.plist; 527 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 528 | PRODUCT_BUNDLE_IDENTIFIER = com.juliobertolacini.ReduxPaperScissorsTests; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | SWIFT_VERSION = 3.0; 531 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReduxPaperScissors.app/ReduxPaperScissors"; 532 | }; 533 | name = Debug; 534 | }; 535 | 60B76ADE1F323BB300223F17 /* Release */ = { 536 | isa = XCBuildConfiguration; 537 | baseConfigurationReference = 23C4C9129821865AD08D683F /* Pods-ReduxPaperScissorsTests.release.xcconfig */; 538 | buildSettings = { 539 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 540 | BUNDLE_LOADER = "$(TEST_HOST)"; 541 | DEVELOPMENT_TEAM = X68268NT2J; 542 | INFOPLIST_FILE = ReduxPaperScissorsTests/Info.plist; 543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 544 | PRODUCT_BUNDLE_IDENTIFIER = com.juliobertolacini.ReduxPaperScissorsTests; 545 | PRODUCT_NAME = "$(TARGET_NAME)"; 546 | SWIFT_VERSION = 3.0; 547 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReduxPaperScissors.app/ReduxPaperScissors"; 548 | }; 549 | name = Release; 550 | }; 551 | /* End XCBuildConfiguration section */ 552 | 553 | /* Begin XCConfigurationList section */ 554 | 60B76AB71F323BB300223F17 /* Build configuration list for PBXProject "ReduxPaperScissors" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | 60B76AD71F323BB300223F17 /* Debug */, 558 | 60B76AD81F323BB300223F17 /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | 60B76AD91F323BB300223F17 /* Build configuration list for PBXNativeTarget "ReduxPaperScissors" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | 60B76ADA1F323BB300223F17 /* Debug */, 567 | 60B76ADB1F323BB300223F17 /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | }; 571 | 60B76ADC1F323BB300223F17 /* Build configuration list for PBXNativeTarget "ReduxPaperScissorsTests" */ = { 572 | isa = XCConfigurationList; 573 | buildConfigurations = ( 574 | 60B76ADD1F323BB300223F17 /* Debug */, 575 | 60B76ADE1F323BB300223F17 /* Release */, 576 | ); 577 | defaultConfigurationIsVisible = 0; 578 | }; 579 | /* End XCConfigurationList section */ 580 | }; 581 | rootObject = 60B76AB41F323BB300223F17 /* Project object */; 582 | } 583 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/Actions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import ReSwift 7 | 8 | // MARK:- ACTIONS 9 | 10 | struct ChooseWeaponAction: Action { 11 | 12 | var weapon: Weapon 13 | } 14 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import ReSwift 8 | 9 | var store = Store(reducer: appReducer, state: nil) 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: 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 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/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 | 31 | 38 | 46 | 53 | 61 | 74 | 87 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/Reducers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import ReSwift 7 | 8 | // MARK:- REDUCERS 9 | 10 | func appReducer(action: Action, state: AppState?) -> AppState { 11 | 12 | // creates a new state if one does not already exist 13 | var state = state ?? AppState() 14 | 15 | switch action { 16 | case let chooseWeaponAction as ChooseWeaponAction: 17 | 18 | let turn = state.turn 19 | switch turn.player { 20 | case .one: 21 | 22 | // create a play 23 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 24 | state.player1Play = play 25 | 26 | // pass the turn to the next player 27 | state.turn = Turn(player: .two) 28 | 29 | // change the message 30 | state.message = .player2choose 31 | 32 | case .two: 33 | 34 | // create a play 35 | let play = Play(chosen: true, weapon: chooseWeaponAction.weapon) 36 | state.player2Play = play 37 | 38 | // calculate who won 39 | let player1weapon = state.player1Play.weapon ?? .rock 40 | let player2weapon = state.player2Play.weapon ?? .rock 41 | 42 | switch player1weapon { 43 | case .rock: 44 | switch player2weapon { 45 | case .rock: 46 | state.result = .draw 47 | state.message = .draw 48 | case .paper: 49 | state.result = .player2wins 50 | state.message = .player2wins 51 | case .scissors: 52 | state.result = .player1wins 53 | state.message = .player1wins 54 | } 55 | case .paper: 56 | switch player2weapon { 57 | case .rock: 58 | state.result = .player1wins 59 | state.message = .player1wins 60 | case .paper: 61 | state.result = .draw 62 | state.message = .draw 63 | case .scissors: 64 | state.result = .player2wins 65 | state.message = .player2wins 66 | } 67 | case .scissors: 68 | switch player2weapon { 69 | case .rock: 70 | state.result = .player2wins 71 | state.message = .player2wins 72 | case .paper: 73 | state.result = .player1wins 74 | state.message = .player1wins 75 | case .scissors: 76 | state.result = .draw 77 | state.message = .draw 78 | } 79 | } 80 | } 81 | 82 | default: 83 | break 84 | } 85 | 86 | // return the new state 87 | return state 88 | } 89 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/State.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import ReSwift 7 | 8 | // MARK:- STATE 9 | 10 | struct AppState: StateType { 11 | 12 | var message: Message 13 | var turn: Turn 14 | var player1Play: Play 15 | var player2Play: Play 16 | var result: Result? 17 | 18 | init() { 19 | 20 | self.message = .player1choose 21 | self.turn = Turn(player: .one) 22 | self.player1Play = Play(chosen: false, weapon: nil) 23 | self.player2Play = Play(chosen: false, weapon: nil) 24 | } 25 | } 26 | 27 | 28 | // MARK:- MODEL & OPTIONS 29 | 30 | enum Message: String { 31 | 32 | case player1choose = "PLAYER 1 - Choose your weapon:" 33 | case player2choose = "PLAYER 2 - Choose your weapon:" 34 | case player1wins = "PLAYER 1 WINS!" 35 | case player2wins = "PLAYER 2 WINS!" 36 | case draw = "DRAW!" 37 | } 38 | 39 | struct Turn { 40 | 41 | var player: Player 42 | } 43 | 44 | enum Player { 45 | 46 | case one 47 | case two 48 | } 49 | 50 | struct Play { 51 | 52 | var chosen: Bool 53 | var weapon: Weapon? 54 | } 55 | 56 | enum Weapon: String { 57 | 58 | case rock = "Rock" 59 | case paper = "Paper" 60 | case scissors = "Scissors" 61 | } 62 | 63 | enum Result { 64 | 65 | case draw 66 | case player1wins 67 | case player2wins 68 | } 69 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissors/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import UIKit 7 | import ReSwift 8 | 9 | class ViewController: UIViewController, StoreSubscriber { 10 | 11 | @IBOutlet weak var message: UILabel! 12 | @IBOutlet weak var placeholder1: UILabel! 13 | @IBOutlet weak var placeholder2: UILabel! 14 | 15 | @IBAction func rockButton(_ sender: Any) { 16 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 17 | } 18 | 19 | @IBAction func paperButton(_ sender: Any) { 20 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 21 | } 22 | 23 | @IBAction func scissorsButton(_ sender: Any) { 24 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 25 | } 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | 30 | store.subscribe(self) 31 | } 32 | 33 | func newState(state: AppState) { 34 | 35 | message.text = state.message.rawValue 36 | 37 | if state.player2Play.chosen { 38 | placeholder1.text = state.player1Play.weapon?.rawValue 39 | placeholder2.text = state.player2Play.weapon?.rawValue 40 | } else { 41 | placeholder1.text = state.player1Play.chosen ? "chosen" : "" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissorsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ReduxPaperScissors/ReduxPaperScissorsTests/ReduxPaperScissorsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Julio Bertolacini on 02/08/17. 3 | // Copyright © 2017 Julio Bertolacini Organization. All rights reserved. 4 | // 5 | 6 | import XCTest 7 | import ReSwift 8 | @testable import ReduxPaperScissors 9 | 10 | class ReduxPaperScissorsTests: XCTestCase { 11 | 12 | // testing whether a rule works. 13 | func test1() { 14 | 15 | let store = Store(reducer: appReducer, state: nil) 16 | 17 | // Player 1 choose 18 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 19 | 20 | // Player 2 choose 21 | store.dispatch(ChooseWeaponAction(weapon: .scissors)) 22 | 23 | // Check result 24 | XCTAssertEqual(store.state.result, .player1wins) 25 | } 26 | 27 | // testing whether another rule works. 28 | func test2() { 29 | 30 | let store = Store(reducer: appReducer, state: nil) 31 | 32 | // Player 1 choose 33 | store.dispatch(ChooseWeaponAction(weapon: .rock)) 34 | 35 | // Player 2 choose 36 | store.dispatch(ChooseWeaponAction(weapon: .paper)) 37 | 38 | // Check result 39 | XCTAssertEqual(store.state.result, .player2wins) 40 | } 41 | 42 | } 43 | --------------------------------------------------------------------------------