투케이2K

26. (ios/swift) 웹뷰 호출 및 자바스크립트 통신 수행 실시 - WKWebView 본문

IOS

26. (ios/swift) 웹뷰 호출 및 자바스크립트 통신 수행 실시 - WKWebView

투케이2K 2021. 10. 24. 20:44

[개발 환경 설정]

개발 툴 : XCODE

개발 언어 : SWIFT


[필요 설정]


[소스 코드 : 웹뷰 메인]

import UIKit

// MARK: [웹뷰를 사용하기 위한 import]
import WebKit

class ViewController: UIViewController , WKNavigationDelegate, WKScriptMessageHandler , WKUIDelegate {

    // MARK: [클래스 상속 설명]
    /*
    1. WKNavigationDelegate : 웹뷰 실시간 로드 상태 감지
    2. WKScriptMessageHandler : 자바스크립트 통신 사용
    3. WKUIDelegate : alert 팝업창 이벤트 감지
    */
    
    
    
    // MARK: [액티비티 메모리 로드 수행 실시]
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print("")
        print("===============================")
        print("[ViewController >> viewDidLoad() : 액티비티 메모리 로드 실시]")
        print("===============================")
        print("")
        
        // [웹뷰 호출 실시]
        webviewInit(_loadUrl: "https://google.com") // get 방식
        //webviewInit(_loadUrl: "https://jsonplaceholder.typicode.com/posts?userId=1&id=1") // post 쿼리 파람 방식
    }
    
    
    
    // MARK: [웹뷰 변수 선언 실시 = 스토리보드 없이 동적으로 생성]
    private var mainWebView: WKWebView? = nil
    // [ViewController 종료 시 호출되는 함수]
    deinit {
        // WKWebView Progress 퍼센트 가져오기 이벤트 제거
        self.mainWebView?.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
    }
    
    
    
    // MARK: [웹뷰 초기 설정 값 정의 실시 및 웹뷰 로드 수행]
    func webviewInit(_loadUrl:String){
        print("")
        print("===============================")
        print("[ViewController >> webviewInit() : 웹뷰 초기 설정 값 정의 실시 및 웹뷰 로드 수행]")
        print("url : \(_loadUrl)")
        print("===============================")
        print("")
        
        // [자바스크립트 통신 경로 지정 실시 : 모두 정의]
        self.addJavaScriptBridgeOpen()
        self.addJavaScriptBridgeClose()
        self.addJavaScriptBridgeTest()
        
        
        // [웹뷰 전체 화면 설정 실시]
        // self.mainWebView = WKWebView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
        self.mainWebView = WKWebView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height), configuration: self.javascriptConfig)
        
        
        // [웹뷰 캐시 삭제 실시]
        WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date(timeIntervalSince1970: 0), completionHandler:{ })
        
        
        // [웹뷰 여백 및 배경 부분 색 투명하게 변경]
        //self.mainWebView?.backgroundColor = UIColor.clear
        //self.mainWebView?.isOpaque = false
        //self.mainWebView?.loadHTMLString("<body style=\"background-color: transparent\">", baseURL: nil)
        
        
        // [웹뷰 옵션값 지정]
        self.mainWebView?.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true  // 자바스크립트 활성화
        self.mainWebView?.navigationDelegate = self // 웹뷰 변경 상태 감지 위함
        self.mainWebView?.allowsBackForwardNavigationGestures = true // 웹뷰 뒤로가기, 앞으로 가기 제스처 사용
        self.mainWebView?.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil) // 웹뷰 로드 상태 퍼센트 확인
        self.mainWebView?.uiDelegate = self // alert 팝업창 이벤트 받기 위함
        
        
        // [웹뷰 화면 비율 설정 및 초기 웹뷰 로드 실시 : get url 주소]
        self.view.addSubview(self.mainWebView!)
        let url = URL (string: _loadUrl) // 웹뷰 로드 주소
        let request = URLRequest(url: url! as URL)
        self.mainWebView!.load(request)
        
        
        // [웹뷰 화면 비율 설정 및 초기 웹뷰 로드 실시 : post query parameters url 주소]
        /*self.view.addSubview(self.mainWebView!)
        let url = URL (string: _loadUrl) // 웹뷰 로드 주소
        var request = URLRequest(url: url! as URL)
        request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        self.mainWebView!.load(request)*/
        
        
        // [웹뷰 화면 비율 설정 및 초기 웹뷰 로드 실시 : 로컬 html 파일]
        /*self.view.addSubview(self.mainWebView!)
        guard let localFilePath = Bundle.main.path(forResource: "javaScriptTest", ofType: "html")
        else {
            print("")
            print("===============================")
            print("[ViewController >> webviewInit() : 웹뷰 로드 수행 시작]")
            print("error : file path is nil")
            print("===============================")
            print("")
            return
        }
        let urlFile = URL(fileURLWithPath: localFilePath)
        let request = URLRequest(url: urlFile)
        self.mainWebView!.load(request as URLRequest)*/
    }
    
    
    
    // MARK: [자바스크립트 통신을 위한 초기화 부분]
    let javascriptController = WKUserContentController()
    let javascriptConfig = WKWebViewConfiguration()
    func addJavaScriptBridgeOpen(){
        print("")
        print("===============================")
        print("[ViewController >> addJavaScriptBridgeOpen() : 자바스크립트 통신 브릿지 추가]")
        print("Bridge : open")
        print("===============================")
        print("")
        
        // [open 브릿지 경로 추가]
        self.javascriptController.add(self, name: "open")
        self.javascriptConfig.userContentController = self.javascriptController
        //self.mainWebView = WKWebView(frame: self.view.bounds, configuration: javascriptConfig)
    }
    func addJavaScriptBridgeClose(){
        print("")
        print("===============================")
        print("[ViewController >> addJavaScriptBridgeClose() : 자바스크립트 통신 브릿지 추가]")
        print("Bridge : close")
        print("===============================")
        print("")
        // [close 브릿지 경로 추가]
        self.javascriptController.add(self, name: "close")
        self.javascriptConfig.userContentController = self.javascriptController
        //self.mainWebView = WKWebView(frame: self.view.bounds, configuration: javascriptConfig)
    }
    func addJavaScriptBridgeTest(){
        print("")
        print("===============================")
        print("[ViewController >> addJavaScriptBridgeTest() : 자바스크립트 통신 브릿지 추가]")
        print("Bridge : test")
        print("===============================")
        print("")
        // [test 브릿지 경로 추가]
        self.javascriptController.add(self, name: "test")
        self.javascriptConfig.userContentController = self.javascriptController
        //self.mainWebView = WKWebView(frame: self.view.bounds, configuration: javascriptConfig)
    }
    
    
    
    // MARK: [자바스크립트 >> IOS 통신 부분]
    @available(iOS 8.0, *)
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        // MARK: [웹 코드] window.webkit.messageHandlers.open.postMessage("[open] 자바스크립트 >> IOS 호출");
        if message.name == "open" { // 브릿지 경로 지정
            let receiveData = message.body // 전달 받은 메시지 확인
            print("")
            print("===============================")
            print("[ViewController >> userContentController() : 자바스크립트 >> IOS]")
            print("Bridge : open")
            print("receiveData : ", receiveData)
            print("===============================")
            print("")
            
            // MARK: [웹 코드] function receive_Open() {} : IOS >> 자바스크립트 데이터 전송 실시
            self.sendFunctionOpen(_send: "") // 널 데이터
        }
        // MARK: [웹 코드] window.webkit.messageHandlers.close.postMessage("[close] 자바스크립트 >> IOS 호출");
        if message.name == "close" { // 브릿지 경로 지정
            let receiveData = message.body // 전달 받은 메시지 확인
            print("")
            print("===============================")
            print("[ViewController >> userContentController() : 자바스크립트 >> IOS]")
            print("Bridge : close")
            print("receiveData : ", receiveData)
            print("===============================")
            print("")
            
            // MARK: [웹 코드] function receive_Close(value) {} : IOS >> 자바스크립트 데이터 전송 실시
            self.sendFunctionClose(_send: "IOS >> 자바스크립트") // 데이터
        }
        // MARK: [웹 코드] window.webkit.messageHandlers.test.postMessage("[test] 자바스크립트 >> IOS 호출");
        if message.name == "test" { // 브릿지 경로 지정
            let receiveData = message.body // 전달 받은 메시지 확인
            print("")
            print("===============================")
            print("[ViewController >> userContentController() : 자바스크립트 >> IOS]")
            print("Bridge : test")
            print("receiveData : ", receiveData)
            print("===============================")
            print("")
            
            // MARK: [웹 코드] function receive_Close(value) {} : IOS >> 자바스크립트 데이터 전송 실시
            self.sendFunctionTest(_send: "") // 널 데이터
        }
    }
    
    
    // MARK: [IOS >> 자바스크립트 통신 부분]
    func sendFunctionOpen(_send:String){
        print("")
        print("===============================")
        print("[ViewController >> sendFunctionOpen() : IOS >> 자바스크립트]")
        print("_send : ", _send)
        print("===============================")
        print("")
        self.mainWebView!.evaluateJavaScript("receive_Open('\(_send)')", completionHandler: nil)
        /*self.mainWebView!.evaluateJavaScript("receive_Open('')", completionHandler: {
            (any, err) -> Void in
            print(err ?? "[receive_Open] IOS >> 자바스크립트 : SUCCESS")
        })*/
    }
    func sendFunctionClose(_send:String){
        print("")
        print("===============================")
        print("[ViewController >> sendFunctionClose() : IOS >> 자바스크립트]")
        print("_send : ", _send)
        print("===============================")
        print("")
        self.mainWebView!.evaluateJavaScript("receive_Close('\(_send)')", completionHandler: nil)
        /*self.mainWebView!.evaluateJavaScript("receive_Close('')", completionHandler: {
            (any, err) -> Void in
            print(err ?? "[receive_Close] IOS >> 자바스크립트 : SUCCESS")
        })*/
    }
    func sendFunctionTest(_send:String){
        print("")
        print("===============================")
        print("[ViewController >> sendFunctionClose() : IOS >> 자바스크립트]")
        print("_send : ", _send)
        print("===============================")
        print("")
        self.mainWebView!.evaluateJavaScript("receive_Test('\(_send)')", completionHandler: nil)
        /*self.mainWebView!.evaluateJavaScript("receive_Test('')", completionHandler: {
            (any, err) -> Void in
            print(err ?? "[receive_Test] IOS >> 자바스크립트 : SUCCESS")
        })*/
    }
    
    
    // [웹뷰 로드 수행 시작 부분]
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        let _startUrl = String(describing: webView.url?.description ?? "")
        print("")
        print("===============================")
        print("[ViewController >> didStartProvisionalNavigation() : 웹뷰 로드 수행 시작]")
        print("url : \(_startUrl)")
        print("===============================")
        print("")
    }
    
    
    // [웹뷰 로드 상태 퍼센트 확인 부분]
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        // 0 ~ 1 사이의 실수형으로 결과값이 출력된다 [0 : 로딩 시작, 1 : 로딩 완료]
        print("")
        print("===============================")
        print("[ViewController >> observeValue() : 웹뷰 로드 상태 확인]")
        print("loading : \(Float((self.mainWebView?.estimatedProgress)!)*100)")
        print("===============================")
        print("")
    }
    
    
    // [웹뷰 로드 수행 완료 부분]
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let _endUrl = String(describing: webView.url?.description ?? "")
        print("")
        print("===============================")
        print("[ViewController >> didFinish() : 웹뷰 로드 수행 완료]")
        print("url : \(_endUrl)")
        print("===============================")
        print("")
    }

    
    // [웹뷰 로드 수행 에러 확인]
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        let _nsError = error as NSError
        let _errorUrl = String(describing: webView.url?.description ?? "")
        print("")
        print("===============================")
        print("[ViewController >> didFail() : 웹뷰 로드 수행 에러]")
        print("_errorUrl : \(_errorUrl)")
        print("_errorCode : \(_nsError)")
        print("_errorMsg : \(S_WebViewErrorCode().checkError(_errorCode: 1019))")
        print("===============================")
        print("")
    }

    
    // [웹뷰 실시간 url 변경 감지 실시]
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let _shouldUrl = String(describing: webView.url?.description ?? "")
        var action: WKNavigationActionPolicy?
        defer {
            decisionHandler(action ?? .allow)
        }
        guard let url = navigationAction.request.url else { return }
        print("")
        print("===============================")
        print("[ViewController >> decidePolicyFor() : 웹뷰 실시간 url 변경 감지]")
        print("_shouldUrl : \(_shouldUrl)")
        print("requestUrl : \(url)")
        print("===============================")
        print("")
    }
    
    
    // [웹뷰 모달창 닫힐때 앱 종료현상 방지]
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
        
    // [alert 팝업창 처리]
    func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
                 initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void){
        print("")
        print("===============================")
        print("[ViewController >> runJavaScriptAlertPanelWithMessage() : alert 팝업창 처리]")
        print("message : ", message)
        print("===============================")
        print("")
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler() }))
        self.present(alertController, animated: true, completion: nil)
    }


    // [confirm 팝업창 처리]
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        print("")
        print("===============================")
        print("[ViewController >> runJavaScriptConfirmPanelWithMessage() : confirm 팝업창 처리]")
        print("message : ", message)
        print("===============================")
        print("")
        let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in completionHandler(false) }))
        alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in completionHandler(true) }))
        self.present(alertController, animated: true, completion: nil)
    }
    

    // [href="_blank" 링크 이동 처리]
    /*func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        print("")
        print("===============================")
        print("[ViewController >> createWebViewWith() : href=_blank 링크 이동]")
        print("===============================")
        print("")
        if navigationAction.targetFrame == nil {
            webView.load(navigationAction.request)
        }
        return nil
    }*/
    
}

[소스 코드 : 웹뷰 에러 코드]

//
//  S_WebViewErrorCode.swift
//  testCode
//
//  Created by lotecs on 2021/10/24.
//

import Foundation

class S_WebViewErrorCode {
    
    
    /*
    [클래스 설명]
    1. 웹뷰 호출 시 발생하는 에러 코드 관리 클래스
    2. 사용 방법 : S_WebViewErrorCode().checkError(_errorCode: 1019)
    */
    
    func checkError(_errorCode:Int) -> String {
        // ========== [일반 에러 정의] ==========
        if _errorCode == NSURLErrorCancelled {
            return "NSURLErrorCancelled [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorUnknown{
            return "NSURLErrorUnknown [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorBadURL{
            return "NSURLErrorBadURL [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorTimedOut{
            return "NSURLErrorTimedOut [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorUnsupportedURL{
            return "NSURLErrorUnsupportedURL [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotFindHost{
            return "NSURLErrorCannotFindHost [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotConnectToHost{
            return "NSURLErrorCannotConnectToHost [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorNetworkConnectionLost{
            return "NSURLErrorNetworkConnectionLost [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorDNSLookupFailed{
            return "NSURLErrorDNSLookupFailed [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorHTTPTooManyRedirects{
            return "NSURLErrorHTTPTooManyRedirects [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorResourceUnavailable{
            return "NSURLErrorResourceUnavailable [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorNotConnectedToInternet{
            return "NSURLErrorNotConnectedToInternet [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorRedirectToNonExistentLocation{
            return "NSURLErrorRedirectToNonExistentLocation [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorBadServerResponse{
            return "NSURLErrorBadServerResponse [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorUserCancelledAuthentication{
            return "NSURLErrorUserCancelledAuthentication [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorUserAuthenticationRequired{
            return "NSURLErrorUserAuthenticationRequired [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorZeroByteResource{
            return "NSURLErrorZeroByteResource [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotDecodeRawData{
            return "NSURLErrorCannotDecodeRawData [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotDecodeContentData{
            return "NSURLErrorCannotDecodeContentData [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotParseResponse{
            return "NSURLErrorCannotParseResponse [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorAppTransportSecurityRequiresSecureConnection{
            return "NSURLErrorAppTransportSecurityRequiresSecureConnection [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorFileDoesNotExist{
            return "NSURLErrorFileDoesNotExist [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorFileIsDirectory{
            return "NSURLErrorFileIsDirectory [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorNoPermissionsToReadFile{
            return "NSURLErrorNoPermissionsToReadFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorDataLengthExceedsMaximum{
            return "NSURLErrorDataLengthExceedsMaximum [ \(String(_errorCode)) ]"
        }
        
        
        
        // ========== [ssl 에러 발생] ==========
        else if _errorCode == NSURLErrorSecureConnectionFailed{
            return "NSURLErrorSecureConnectionFailed [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorServerCertificateHasBadDate{
            return "NSURLErrorServerCertificateHasBadDate [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorServerCertificateUntrusted{
            return "NSURLErrorServerCertificateUntrusted [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorServerCertificateHasUnknownRoot{
            return "NSURLErrorServerCertificateHasUnknownRoot [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorServerCertificateNotYetValid{
            return "NSURLErrorServerCertificateNotYetValid [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorClientCertificateRejected{
            return "NSURLErrorClientCertificateRejected [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorClientCertificateRequired{
            return "NSURLErrorClientCertificateRequired [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotLoadFromNetwork{
            return "NSURLErrorCannotLoadFromNetwork [ \(String(_errorCode)) ]"
        }
        
        
        
        // ========== [파일 관련 에러] ==========
        else if _errorCode == NSURLErrorCannotCreateFile{
            return "NSURLErrorCannotCreateFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotOpenFile{
            return "NSURLErrorCannotOpenFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotCloseFile{
            return "NSURLErrorCannotCloseFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotWriteToFile{
            return "NSURLErrorCannotWriteToFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotRemoveFile{
            return "NSURLErrorCannotRemoveFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCannotMoveFile{
            return "NSURLErrorCannotMoveFile [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorDownloadDecodingFailedMidStream{
            return "NSURLErrorDownloadDecodingFailedMidStream [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorDownloadDecodingFailedToComplete{
            return "NSURLErrorDownloadDecodingFailedToComplete [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorInternationalRoamingOff{
            return "NSURLErrorInternationalRoamingOff [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorCallIsActive{
            return "NSURLErrorCallIsActive [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorDataNotAllowed{
            return "NSURLErrorDataNotAllowed [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorRequestBodyStreamExhausted{
            return "NSURLErrorRequestBodyStreamExhausted [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorBackgroundSessionRequiresSharedContainer{
            return "NSURLErrorBackgroundSessionRequiresSharedContainer [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorBackgroundSessionInUseByAnotherProcess{
            return "NSURLErrorBackgroundSessionInUseByAnotherProcess [ \(String(_errorCode)) ]"
        }
        else if _errorCode == NSURLErrorBackgroundSessionWasDisconnected{
            return "NSURLErrorBackgroundSessionWasDisconnected [ \(String(_errorCode)) ]"
        }
        
        
        
        // ========== [else 처리] ==========
        else {
            return "else [ \(String(_errorCode)) ]"
        }
    }
}

 


[결과 출력]


 

반응형
Comments