Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 리팩토링
- UICollectionView
- Refactoring
- swift documentation
- ios
- uiscrollview
- 클린 코드
- 리펙터링
- Protocol
- rxswift
- 스위프트
- Clean Code
- collectionview
- map
- Observable
- combine
- Xcode
- swiftUI
- 리펙토링
- clean architecture
- uitableview
- SWIFT
- 애니메이션
- ribs
- tableView
- UITextView
- RxCocoa
- MVVM
- HIG
- Human interface guide
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] Observable로 start, cancel할 수 있는 task 구현 (DispatchWorkItem, Operation 기능) 본문
iOS 응용 (swift)
[iOS - swift] Observable로 start, cancel할 수 있는 task 구현 (DispatchWorkItem, Operation 기능)
jake-kim 2022. 2. 10. 23:55
사용한 framework
pod 'RxSwift'
pod 'RxCocoa'
시작, 취소 기능을 Observable로 구현
- DispatchWorkItem과 Operation을 사용하여 task들을 관리할 수 있지만 Observable를 사용하면 더욱 단순화
* Operation 포스팅 글 참고
* DispatchWorkItem 포스팅 글 참고 - Observable을 사용하면 다양한 Rx 연산자 사용이 가능하여 다른 기능을 붙이기에 용이
시작, 취소 기능 구현 아이디어
- 시작 기능
- 시작 버튼을 탭하면 task를 시작하고, 만약 기존에 task가 실행중이면 내부적으로 취소한 후 실행
- Observable로 task를 관리하면, disposeBag = DisposeBag()과 같이 초기화하여 기존 작업을 손쉽게 취소 가능
- 취소 기능
- 작업중인 스트림을 초기화 disposeBag = DisposeBag()
구현
- 사용하는 쪽에서는 startTask(), cancelTask()로 사용
import UIKit class ViewController: UIViewController { @IBOutlet weak var startButton: UIButton! @IBOutlet weak var cancelButton: UIButton! override func viewDidLoad() { super.viewDidLoad() } @IBAction func didTapStartButton(_ sender: Any) { MyPopup.startTask() } @IBAction func didTapCancelButton(_ sender: Any) { MyPopup.cancelTask() } }
- protocol 정의
protocol MyPopupType { static func startTask() static func cancelTask() }
- 구현에 앞서서, window의 맨 위에 팝업을 띄워야 하므로, topViewController에 접근하는 코드를 UIApplication+Extension에 추가
// UIApplication+Extension.swift import UIKit // https://stackoverflow.com/questions/36284476/top-most-viewcontroller-under-uialertcontroller extension UIApplication { var rootViewController: UIViewController? { self.windows.compactMap(\.rootViewController).first } class var topViewController: UIViewController? { UIApplication.shared.rootViewController .flatMap(self.topViewController(base:)) } private class func topViewController(base: UIViewController?) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return topViewController(base: selected) } } if let page = base as? UIPageViewController, page.viewControllers?.count == 1 { return topViewController(base: page.viewControllers?.first) } if let alert = base as? UIAlertController { if let presenting = alert.presentingViewController { return topViewController(base: presenting) } } if let presented = base?.presentedViewController { return topViewController(base: presented) } for subview in base?.view.subviews ?? [] { if let childVC = subview.next as? UIViewController { return topViewController(base: childVC) } } return base } }
- MyPopup 구현 준비
class MyPopup: MyPopupType { static private var disposeBag = DisposeBag() static private var countDown = 3 static func startTask() { } static func cancelTask() { } }
- cancelTask() 구현
static func cancelTask() { Self.disposeBag = DisposeBag() }
- startTask() 구현
- 기존 작업 먼저 취소
static func startTask() { Self.cancelTask() // 이어서 구현 }
- 카운트 다운이 들어갈 label 생성
-
let sampleLabel = UILabel() sampleLabel.backgroundColor = .systemOrange sampleLabel.textColor = .white sampleLabel.font = .systemFont(ofSize: 32) sampleLabel.textAlignment = .center guard let superview = UIApplication.topViewController?.view else { return } superview.addSubview(sampleLabel) sampleLabel.translatesAutoresizingMaskIntoConstraints = false sampleLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true sampleLabel.heightAnchor.constraint(equalToConstant: 300).isActive = true sampleLabel.centerYAnchor.constraint(equalTo: superview.centerYAnchor).isActive = true sampleLabel.centerXAnchor.constraint(equalTo: superview.centerXAnchor).isActive = true
- Task 정의: Observable<Void>.create로 정의하고 작업이 끝난 경우, observer.onCompleted()를 하고, Disposables.create에서는 removeFromSuperview()를 사용하여 해제하도록 구현
Observable<Void> .create { [weak sampleLabel] observer in Observable<Int>.timer(.seconds(0), period: .seconds(1), scheduler: MainScheduler.instance) .take(Self.countDown + 1) .subscribe(onNext: { timePassed in let count = Self.countDown - timePassed sampleLabel?.text = "\(count)" }, onCompleted: { sampleLabel?.removeFromSuperview() observer.onCompleted() }) .disposed(by: Self.disposeBag) return Disposables.create { sampleLabel?.removeFromSuperview() } } .subscribe() .disposed(by: Self.disposeBag) } // end, startTask()
- 기존 작업 먼저 취소
* 전체 코드: https://github.com/JK0369/ExObservable
* 참고
https://stackoverflow.com/questions/36284476/top-most-viewcontroller-under-uialertcontroller
'iOS 응용 (swift)' 카테고리의 다른 글
Comments