| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
by Seok
Button의 다형성 구현을 위하여 ButtonController 및 ButtonMapper 객체 생성
import UIKit
enum ViewControllerType: CaseIterable {
case giftVC
case advertiseVC
case rankVC
case itemVC
}
final class ButtonMapper {
private var map: [UIButton: ViewControllerType]
init(from buttons: [UIButton]) {
self.map = Dictionary(uniqueKeysWithValues: zip(buttons, ViewControllerType.allCases))
}
subscript(button: UIButton) -> ViewControllerType? {
return map[button]
}
}
final class ButtonController: NSObject {
@IBOutlet var moveToVCButtons: [UIButton]!
private var moveToVCMapper: ButtonMapper?
private var buttonTouchedHandler: (ViewControllerType) -> ()
override init() {
buttonTouchedHandler = { _ in }
}
func setupButton() {
self.moveToVCMapper = ButtonMapper(from: moveToVCButtons)
}
@IBAction func buttonTouched(sender: UIButton) {
guard let vc = moveToVCMapper?[sender] else { return }
buttonTouchedHandler(vc)
}
func bind(action: @escaping (ViewControllerType) -> ()) {
self.buttonTouchedHandler = action
}
}이때 SceneCoordinator 생성하여 진행할지 회의 필요 -> SceneCoordinator로 구현하기로 협의하여 객체생성
import Foundation
import RxSwift
import RxCocoa
final class SceneCoordinator: SceneCoordinatorType {
private var window: UIWindow
private var currentVC: UIViewController
required init(window: UIWindow) {
self.window = window
currentVC = window.rootViewController!
}
@discardableResult
func transition(to scene: Scene, using style: TransitionStyle, animated: Bool) -> Completable {
let subject = PublishSubject<Void>()
let target = scene.instantiate()
switch style {
case .root:
currentVC = target
window.rootViewController = target
subject.onCompleted()
case .fullScreen:
target.modalPresentationStyle = .fullScreen
currentVC.present(target, animated: animated) {
subject.onCompleted()
}
currentVC = target
case .modal:
currentVC.present(target, animated: animated) {
subject.onCompleted()
}
currentVC = target
}
return subject.ignoreElements().asCompletable()
}
@discardableResult
func close(animated: Bool) -> Completable {
let subject = PublishSubject<Void>()
if let presentingVC = self.currentVC.presentingViewController {
self.currentVC.dismiss(animated: animated) {
self.currentVC = presentingVC
subject.onCompleted()
}
} else {
subject.onError(TransitionError.unknown)
}
return subject.ignoreElements().asCompletable()
}
}ViewController가 ViewModel로 Button이 가지고있는 ViewControllerType을 넘기면 VC 이동기능 구현
import Foundation
class MainViewModel:CommonViewModel {
func makeMoveAction(to viewController: ViewControllerType) {
switch viewController {
case .giftVC:
let giftViewModel = GiftViewModel(sceneCoordinator: self.sceneCoordinator)
let giftScene = Scene.gift(giftViewModel)
self.sceneCoordinator.transition(to: giftScene, using: .modal, animated: true)
case .advertiseVC:
let advertiseViewModel = AdvertiseViewModel(sceneCoordinator: self.sceneCoordinator)
let advertiseScene = Scene.ad(advertiseViewModel)
self.sceneCoordinator.transition(to: advertiseScene, using: .fullScreen, animated: true)
case .rankVC:
let rankViewModel = RankViewModel(sceneCoordinator: self.sceneCoordinator)
let rankScene = Scene.rank(rankViewModel)
self.sceneCoordinator.transition(to: rankScene, using: .modal, animated: true)
case .itemVC:
let itemViewModel = ItemViewModel(sceneCoordinator: self.sceneCoordinator)
let itemScene = Scene.item(itemViewModel)
self.sceneCoordinator.transition(to: itemScene, using: .modal, animated: true)
}
}
}추후 로직에 따라 Storage 등의 추가 객체가 필요하면 CommonViewModel의 init에 주입하여 SceneDelegate에서 넣어주면 쉽게 코드 변경 가능
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let coordinator = SceneCoordinator(window: window!)
let mainViewModel = MainViewModel(sceneCoordinator: coordinator)
let mainScene = Scene.main(mainViewModel)
coordinator.transition(to: mainScene, using: .root, animated: false)
}by Seok
GiftVC & ViewModel 객체 생성 및 CancelButton 기능구현
import Foundation
import Action
class GiftViewModel: CommonViewModel {
let confirmAction: Action<String, Void>
let cancelAction: CocoaAction
init(sceneCoordinator: SceneCoordinatorType, storage: ItemStorageType, confirmAction: Action<String, Void>? = nil ,cancelAction: CocoaAction? = nil) {
self.confirmAction = Action<String, Void> { input in
if let action = confirmAction {
action.execute(input)
}
return sceneCoordinator.close(animated: true).asObservable().map{ _ in }
}
self.cancelAction = CocoaAction {
if let action = cancelAction {
action.execute(())
}
return sceneCoordinator.close(animated: true).asObservable().map{ _ in }
}
super.init(sceneCoordinator: sceneCoordinator, storage: storage)
}
}by Seok
SceneCoordinator Transition Method Refactoring
import Foundation
import RxSwift
protocol SceneCoordinatorType {
@discardableResult
func transition(to scene: Scene, using style: TransitionStyle, with type: StoryboardType, animated: Bool) -> Completable
@discardableResult
func close(animated: Bool) -> Completable
@discardableResult
func toMain(animated: Bool) -> Completable
}Disable SwiftLint Waring
// swiftlint:disable:next cyclomatic_complexity
func instantiate(from storyboard: String) -> UIViewControllerStoryboardType enum타입 생성
import Foundation
enum StoryboardType {
case main
case game
var name: String {
switch self {
case .main:
return "Main"
case .game:
return "Game"
}
}
}GhostTypewriter 라이브러리 추가
import UIKit
import GhostTypewriter
final class MainViewController: UIViewController, ViewModelBindableType {
var viewModel: MainViewModel!
@IBOutlet var buttonController: MainButtonController!
@IBOutlet weak var titleLabel: TypewriterLabel!
override func viewDidLoad() {
super.viewDidLoad()
titleLabel.startTypewritingAnimation()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
titleLabel.restartTypewritingAnimation()
}
}created by 우송
| Back | FazBrowse Home | New Git URL |