IT/Swift

AppDelegate & ViewController

종금 2017. 12. 10. 23:59
반응형

우리가 Xcode를 실행하여 제일 기본적인 Single View app을 통해 프로젝트를 생성하면 우리는 기본 코드로 AppDelegate 파일과 ViewController 파일을 볼 수 있다.

왜 스위프트는 위 두가지 소스 파일을 기본적으로 제공해 줄까? 위 궁금증이 계속 되던 순간 앱 12개를 만들며 배우는 Swift3 & IOS10을 통해 배우게 되었고 정리하는 글이다.


위의 소스들은 IOS가 제공해주는 코코아터치에 관련되어 있다.

우리가 IOS에서 어플을 실행하기 위해서는 터치를 통해 어플의 아이콘을 눌러야 한다는 기본적인 전제를 깔고 있다.

이는 백그라운드(Background)에서 포어그라운드(Foreground) 상태로 넘어가는 것을 의미하며 또한 반대로 포어그라운드에서 백그라운드로 넘어가는 상황에서 실행되는 코드들을 스위프트에서 기본적으로 제공해준다.

너무 당연한 것일지 모른다. 우리가 어떤 장르의 어플을 만들더라도 어플에 진입하는 것과 나가는 것은 어떤 어플에서든 필요한 가장 필수적으로 필요한 코드이기 때문이다.


그러면 먼저 우리는 IOS의 하드웨어에서 어플을 실행할 때 어떤 방식으로 실행 되는지부터 알아야한다.

이는 애플에서 제공해주는 가이드에 잘 나오고 있는데 아래의 사진과 같다.



첫번째로 우리는 어플의 아이콘을 터치한다. 그러면 어플의 메인함수로 넘어가게 되고 그중에서 UI(user interface)의 메인을 불러오게 된다.

유저의 메인 인터페이스를 불러오게 되면 첫 시작으로 willFinishLaunchingwithOptions라는 코드가 AppDelegate에서 실행되며 만약 실행과정에서 실행시키고 싶은 이벤트가 있다면 우리는 이부분을 고쳐서 이벤트가 실행 될 수 있게 할 수 있다. 이후 어플이 실행될 때 필요한 이벤트 과정이 끝나면 초기화가 끝난다는 didFinishLaunchingwithOptions라는 코드가 실행되며 어플이 UI로 넘어가며 실행되고 이후 어플이 홈버튼의 클릭을 통하여 백그라운드로 넘어갈 때는 AppDelegate에서 applicationDidBecomeActive로 되며 만약 백그라운드에서 실행되야하는 어플(음악어플) 일경우 이벤트 루프가 계속 돌아다니며 다른 어플로 스위치 되어지는 구조를 가지고 있다.


자 그러면 본론으로 가서 기본 제공 소스 파일을 분석해보도록 하자


먼저 AppDelegate파일이다.

AppDelegate는 어플이 실행되면 제일 먼저 읽어들이는 소스파일이다. 코드는 다음과 같은데

 import UIKit


@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {


    var window: UIWindow?


    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

        print("willFinishLaunchingWithOptions")

        return true

    }


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // Override point for customization after application launch.

        print("didFinishLaunchingWithOptions")

//        window?.rootViewController = ViewController()

        

        return true

    }


    

}


먼저 AppDelegate 소스는 UIkit를 기반의 UIResponder와 UIApplicationDelegate를 기반으로하고 있는 소스이다.

먼저 var window: UIwindow가 보이는데 이는 UI창을 의미한다.

이후 앱이 실행되는 순간의 코드 두가지(willFinishLaunchingWithOptions, didFinishLaunchingWithOptions)가 나온다.

실은 willFinish...의 코드는 기본으로 아직 제공해주지는 않고 있는 코드이다. 이 코드는 어플을 터치하여 실행시킬때 시작되지만 상태의 대한 저장값은 이루어지지 않을 때 사용되는 코드로 정의하고 있다. 아주 짧은시간이지만 무엇인가의 이벤트를 줄 때 사용할 수 있을 것으로 보인다. 이후 곧장 didFinish...의 코드가 사용 되어 지는 것을 볼 수 있는데 이는 어플이 사용할 준비가 완료 되었다는 것을 알려주는 코드이다. 위 코드는 어플이 처음 실행 되어 메모리에 올라가는 그 순간에만 실행되어진다.


이후 우리는 어플실행 준비가 다 되었기 때문에 AppDelegate의 다른 코드가 실행되지 않고 ViewController로 넘어가게 되는 것을 알 수 있다. ViewController에 있는 소스중 아래의 소스는 우리가 공부할 소스 몇가지를 추가하여 적은 소스이다.


import UIKit


class ViewController: UIViewController {


    override func loadView() {

        super.loadView()

        print("loadView")

        //no use interface using hardcore coding but using super u can use storyboard

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()

        print("viewDidLoad")

        // Do any additional setup after loading the view, typically from a nib.

        // view on the memory

    }

    

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(true)

        print("viewWillAppear")

        //move view it called

    }

    

    override func viewDidAppear(_ animated: Bool) {

        super.viewDidAppear(true)

        print("viewDidAppear")

        //view move ended

    }

     



위의 코드를 보면 원래 존재하지 않는 코드도 많기에 자세히 설명하겠다. 우리는 대체적으로 Main.storyboard를 통해 UI 디자인을 한다. 하지만 스토리보드로 불가능 한 경우 하드코딩이 필요한데 그때 우리는 loadView를 통하여 코딩을 통해 UI를 구현할 수 있다. 하지만 loadView 코드를 구현하면 스토리보드의 UI를 가지고 올 수 없게 되어 스토리보드를 꾸며도 검정화면만 나오게 된다. 그 것을 해결하는 방안으로는 super.loadView 코드를 구현하여 사용하면 스토리보드 또한 사용할 수 있게 되고 loadView는 어플이 시작되어지는 순간 가장 먼저 사용되는 UI 코드이다. 이후 사용되어지는 코드는 ViewDidLoad이다. ViewDidLoad란 ViewController파일이 메모리에 처음 실행되는 순간 실행되는 코드이다. 파일이 메모리에 올라가면 viewWillAppear 코드가 실행되어 우리가 만든 컨트롤러를 화면에 띄울 준비가 되어 졌다고 알려주며 화면에 전부 띄어지면 viewDidAppear의 코드가 실행되며 어플이 실행된다.


하지만 어플이 실행되는 순간에만 AppDelegate와 ViewController가 실행되는 것이 아니다.

우리가 화면을 바꾸는 순간 혹은 앱을 나가는 순간에도 실행이 되는데 이번에는 그 순간에 대해 적어보도록 하겠다.

한 뷰컨트롤러에서 새로운 뷰컨트롤러로 이동할 때는 뷰가 사리잔다고 알려준다 이때 기준은 메인 뷰컨트롤러이다.

만약 버튼을통해 새로운 뷰 컨트롤러로 넘어가면 아래의 코드가 실행된다.


        

    override func viewWillDisappear(_ animated: Bool) {

        super.viewWillDisappear(true)

        print("viewWillDisappear")

    }

    

    override func viewDidDisappear(_ animated: Bool) {

        super.viewDidDisappear(true)

        print("viewDidDisappear")

    }  


바로 viewWillDisappear과 viewDidDisappear인데 메인 뷰가 사라진다고 알려주며 이때 사용될 이벤트를 Will과 Did코드 사이에 넣어주면 된고 다시 첫 실행 화면으로 돌아가는 버튼을 누른다면 viewWillAppear과 viewDidAppear 코드가 실행된다.(viewDidLoad의 경우는 메모리에 올라가는 순간이기 때문에 첫 어플 시작때만 실행 된다.)


어플을 작동할 때는 화면의 이동만 있는 것이 아니다. 전화가 왔다거나 어떤 다른 일을 하기 위해 백그라운드로 넘어가는 순간도 있다. 이때는 AppDelegate 파일에서 코딩이 이루어진다.


    func applicationWillResignActive(_ application: UIApplication) {

        print("applicationWillResignActive")

        // 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.

        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.

    }


    func applicationDidEnterBackground(_ application: UIApplication) {

        print("applicationDidEnterBackground")

        // 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.

        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    }


    func applicationWillEnterForeground(_ application: UIApplication) {

        print("applicationWillEnterForeground")

        // 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.

    }


    func applicationDidBecomeActive(_ application: UIApplication) {

        // 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.

        print("applicationDidBecomeActive")

    }


 


위의 코딩을 해석하면 다음과 같다 우리가 물리적 버튼인 홈버튼을 누르면 어플이 종료가 되는 것이 아닌 백그라운드로 넘어가며 어플이 잠시 일시정지 상태로 넘어가게 된다. 이때 중요한 것이 있다. 바로 리소스를 릴리즈해주고 현재까지 했던 내용을 저장해주는 것인데 이는 applicationDidEnterBackground에서 이루어진다. 이때 리소를 릴리즈 하지 않게 된다면 다시 어플을 실행 했을때 로딩이 필요 없기에 편한 상황이 올 수 있지만 위와 같은 어플이 쌓인다면 하드웨어에 부담을 줄 것이기에 리소스를 릴리즈 해주는 일은 중요하다. 또한 리소스를 릴리즈해주면서 지금까지의 데이터를 저장해주는 것 또한 중요하다. 홈버튼을 눌러 나가는 것은 자신의 의지에 의해 나가는 것이지만 전화가 온다거나 알람 같이 자신의 의지와 별개로 이루어지는 백그라운드 진입도 존재한다. 이때 중요한 데이터를 저장 중이었다면 전부 사라지는 낭패를 볼 수 있기에 백그라운드 진입시에는 저장할 수 있도록 만들어 주는 것이 중요하다.

이후 다시 어플로 진입하게 된다면 applicationWillEnterForeground와 applicationDidBecomeActive를 통해 어플이 다시 시작되었다는 것을 알려주며 유저 인터페이스가 다시 실행되지만 ViewController의 소스 파일은 실행되지 않는 것을 보아 저장되어진 그상태 그대로 불러들여 예전에 불러 들인 ViewController 소스를 사용한다고 예상되어진다.


마지막으로 어플을 홈버튼 두번 클릭하여 스와이프를 통해 강제 종료를 하게되면 어플은 그대로 모든 기능이 정지되게 된다. 이때 사용되는 소스코드는 다음과 같다.

 

func applicationWillTerminate(_ application: UIApplication) {

        print("applicationWillTerminate")

        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.

    } 


물론 백그라운드 진입과정과 굉장히 비슷하게 데이터를 저장하고 리소를 더이상 사용하지 않을 것이므로 applicationDidEnterBackground로 대체할 수 있기도 한 코드이며 한동안 사라졌던 코드이기도 하다. 하지만 백그라운드 진입때 리소스 쉐어를 안하고 싶다면 이 코드를 사용한다면 예기치 못한 상황에서 종료시에 리소스를 지키고 사용자가 원하는 상황에서만 리소스 쉐어를 할 수 있을 것으로 보인다.

     







반응형

'IT > Swift' 카테고리의 다른 글

Thread 1: Signal SIGABART의 고찰  (1) 2017.11.26
스위프트 가이드 ver.2  (0) 2017.11.11
Swift 가이드 ver.1  (0) 2017.11.09