Skip to content

Instantly share code, notes, and snippets.

@ppth0608
Last active July 13, 2019 08:20
Show Gist options
  • Save ppth0608/aaae886695cb71f1ee0976692789693d to your computer and use it in GitHub Desktop.
Save ppth0608/aaae886695cb71f1ee0976692789693d to your computer and use it in GitHub Desktop.
Refactoring the function 'didFinishLaunchingWithOptions' in the `AppDelegate' file using the class 'Launcher'
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var launcher: Laucher?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
launcher = AppLauncher(application: application, launchItem: AppLaunchItem(window: window))
launcher?.launch()
return true
}
}
protocol Executable {
typealias ExecutionCompletionBlock = (() -> Void)?
typealias ExecuteAction = (ExecutionCompletionBlock) -> Void
var isSynchronous: Bool { get }
var execute: ExecuteAction { get }
}
struct Executor {
static func excutes(for executables: [Executable], queue: DispatchQueue = defaultProcessQueue) {
let semaphore = DispatchSemaphore(value: 0)
let workItems: [DispatchWorkItem] = executables.compactMap { type in
DispatchWorkItem {
DispatchQueue.main.async {
let executeBlock: (() -> Void)? = type.isSynchronous ? { semaphore.signal() } : nil
type.execute(executeBlock)
}
if type.isSynchronous {
semaphore.wait()
}
}
}
queue.async {
workItems.forEach {
$0.perform()
$0.wait()
}
}
}
private static let defaultProcessQueue = DispatchQueue(label: "ExecutionServiceQueue", attributes: .concurrent)
}
struct KingfisherTransitionExecution: Executable {
var isSynchronous: Bool {
return false
}
var execute: ExecuteAction {
return { completion in
completion?()
KingfisherManager.shared.defaultOptions = [.transition(.fade(0.2))]
}
}
}
protocol Laucher {
var launchItem: LaunchItem { get }
func launch()
}
class AppLauncher: Laucher {
let application: UIApplication
let launchItem: LaunchItem
init(application: UIApplication, launchItem: LaunchItem) {
self.application = application
self.launchItem = launchItem
}
func launch() {
Executor.excutes(for: launchItem.executables)
}
}
protocol LaunchItem {
var executables: [Executable] { get }
}
struct AppLaunchItem: LaunchItem {
let window: UIWindow
enum `Type` {
case imageTransition
case rxResource
case tutorial(UIWindow)
case recentClip(UIWindow)
case notificationBanner
var executableItem: Executable {
switch self {
case .imageTransition: return KingfisherTransitionExecution()
case .rxResource: return RxResourceExecution()
case .tutorial(let window): return TutorialExecution(window: window)
case .recentClip(let window): return RecentClipExecution(window: window)
case .notificationBanner: return NotificationBannerExecution()
}
}
}
var executables: [Executable] {
let allCases: [Type] = [
.imageTransition, .rxResource, .tutorial(window), .recentClip(window), .notificationBanner
]
return allCases.map { $0.executableItem }
}
init(window: UIWindow) {
self.window = window
}
}
struct NotificationBannerExecution: Executable {
var isSynchronous: Bool {
return false
}
var execute: ExecuteAction {
return { completion in
guard NotificationBannerChecker().check() else {
completion?()
return
}
let urlString = PasteboardAnalyser.newCopiedURL?.absoluteString ?? ""
let banner = NotificationBanner(title: "배너를 눌러 앱에 저장해보세요",
subtitle: urlString,
rightView: UIImageView(image: #imageLiteral(resourceName: "icWebViewForward")),
style: .info)
banner.backgroundColor = #colorLiteral(red: 0.3098039216, green: 0.4117647059, blue: 0.4980392157, alpha: 1)
banner.onTap = {
let vc = AddClipViewController.create(of: .add).then {
$0.viewModel = AddClipViewModel(provider: ServiceProvider.default, urlString: urlString)
}
Navigator.present(vc, animated: true)
}
banner.show()
completion?()
}
}
}
struct NotificationBannerChecker: Checker {
func check() -> Bool {
return PasteboardAnalyser.newCopiedURL?.absoluteString != nil
}
}
struct RecentClipExecution: Executable {
let window: UIWindow
var isSynchronous: Bool {
return true
}
var execute: ExecuteAction {
return { completion in
let nvc = NavigationController.create(of: .navigation)
let vc = RecentClipListViewController.create(of: .recent).then {
$0.viewModel = RecentClipListViewModel(provider: ServiceProvider.default)
}
nvc.viewControllers = [vc]
self.window.rootViewController = nvc
self.window.makeKeyAndVisible()
completion?()
}
}
init(window: UIWindow) {
self.window = window
}
}
struct RxResourceExecution: Executable {
var isSynchronous: Bool {
return false
}
var execute: ExecuteAction {
return { completion in
completion?()
#if Debug
_ = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.map { _ in RxSwift.Resources.total }
.distinctUntilChanged()
.subscribe(onNext: { count in
print("[Rx Resource count] - \(count)")
})
#endif
}
}
}
struct TutorialExecution: Executable {
let window: UIWindow
var isSynchronous: Bool {
return true
}
var execute: ExecuteAction {
return { completion in
guard TutorialChecker().check() else {
completion?()
return
}
let vc = TutorialPageViewController.create(of: .tutorial).then {
$0.viewModel = TutorialViewModel(completion: completion)
}
self.window.rootViewController = vc
self.window.makeKeyAndVisible()
}
}
init(window: UIWindow) {
self.window = window
}
}
struct TutorialChecker: Checker {
func check() -> Bool {
return !Defaults[.didPresentTutorial]
}
}
extension DefaultsKeys {
static let didPresentTutorial = DefaultsKey<Bool>("didPresentTutorial")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment