---
# System prepended metadata

title: Untitled

---

## 問題

![](https://i.gyazo.com/08c1e69f4e8b3b19400f44fe493a9a6e.png)

上記のように、ボタンを押したらリクエストが発生して、いいねできる画面があります。 `FavoriteButton.isFavorited` の値を変えると見た目が変わります。

1. リクエストが完了してからいいねボタンの見た目を変えていますが、APIのレスポンスが遅いとボタンの反応が遅いと思われてしまいます。リクエスト前にボタンの見た目を変えるように変更してください
2. リクエストが失敗したら、いいねボタンの見た目を元に戻してください
3. いいねボタンが連打されてもリクエストが大量に発生しないようにしてください

※いいねの解除は実装しなくて大丈夫です
※MVP版とReactorKit版と素ViewController版があるので好きなテンプレートを使ってください。どのテンプレートを使っても問題ありませんが、素ViewControllerのテンプレートを選んだ場合は、この実装の問題点を教えてください。テンプレートを使わなくても構いません。
※コードの正確性は求めていないので、雰囲気で動けばOKです
※わからないことがあったらインターネットで調べずに、面接官に聞いてください

### MVP版テンプレート
```swift
protocol IllustPresenterInput: AnyObject {
    func onFavorited()
}

protocol IllustPresenterOutput: AnyObject {
    func setIsFavorited(_ isFavorited: Bool)
    func setIsEnabled(_ isEnabled: Bool)
}

final class IllustViewController: UIViewController {
    @IBOutlet private weak var favoriteButton: FavoriteButton! {
        didSet {
            favoriteButton.addTarget(self, action: #selector(handleTapped(_:)), for: .touchUpInside)
        }
    }
    
    var presenter: IllustPresenter?

    @objc func handleTapped(_ sender: UIButton) {
        presenter.onFavorited()
    }
}

extension IllustViewController: IllustPresenterOutput {
    func setIsFavorited(_ isFavorited: Bool) {
        favoriteButton.isFavorited = isFavorited
    }
    
    func setIsEnabled(_ isEnabled: Bool) {
        favoriteButton.isUserInteractionEnabled = isEnabled
    }
}

final class IllustPresenter: IllustPresenterInput {
    init(favoriteRepository: FavoriteRepository) {
        self.favoriteRepository = favoriteRepository
    }
    
    private weak var view: IllustPresenterOutput!
    private let favoriteRepository: FavoriteRepository
    
    func onFavorited() {
        view.setIsFavorited(true)
        view.setIsEnabled(false)
        favoriteRepository.favorite { result in
            view.setIsEnabled(true)
            switch result {
            case .success:
                break
            case let .failure(error):
                // エラー処理
                view.setIsFavorited(false)
            }
        }
    }
}
```

### ReactorKit版テンプレート
```swift
final class IllustViewController: UIViewController, StoryboardView {
    @IBOutlet private weak var favoriteButton: FavoriteButton!

    typealias Reactor = IllustReactor
    var disposeBag = DisposeBag()

    func bind(reactor: Reactor) {
        favoriteButton.rx.tap
            .map { Reactor.Action.favorite }
            .bind(reactor.action)
            .disposed(by: disposeBag)
            
        reactor.state.map { $0.isFavorited }
            .bind(to: favoriteButton.rx.isFavorited)
            .disposed(by: disposeBag)
    }
}

final class IllustReactor: Reactor {
    init(favoriteRepository: FavoriteRepository) {
    	self.favoriteRepository = favoriteRepository
    }
    
    private let favoriteRepository: FavoriteRepository
    
    enum Action {
    	case favorite
    }
    
    enum Mutation {
    	case setFavorited(_ isFavorited: Bool)
    }
    
    struct State {
        var isFavorited: Bool = false
    }
    
    func mutate(action: Action) -> Observable<Mutation> {
        switch action {
        case favorite:
            return favoriteRepository.favorite()
                .flatMap { .just(.setFavorited(true)) }
                .catchError { error in .empty() }
        }
    }

    func reduce(state: State, mutation: Mutation) -> State {
        var state = state
        switch mutation {
        case let .setFavorited(isFavorited):
            state.isFavorited = isFavorited
        }
        return state
    }
}
```

### 素ViewController版テンプレート
```swift
final class IllustViewController: UIViewController {
    @IBOutlet private weak var favoriteButton: FavoriteButton! {
        didSet {
            favoriteButton.addTarget(self, action: #selector(handleTapped(_:)), for: .touchUpInside)
        }
    }
    
    private let repository = FavoriteRepository()

    @objc func handleTapped(_ sender: UIButton) {
        favoriteRepository.favorite { result in
            switch result {
            case .success:
                favoriteButton.isFavorited = true
            case let .failure(error):
                // エラー処理
            }
        }
    }
}
```