present()로 띄운 UIViewController의 WKWebView에서 사진 첨부를 하면 UIViewController가 닫혀(dismiss()) 버린다.

present() 로 띄운 UIViewController에 있는 UIWebView/WKWebView에서 input type=”file” / 을 눌러서 사진을 첨부하려 하면 해당 UIViewController까지 함께 닫혀 버리는 문제가 있습니다.

이 문제는 iOS 8.0.2 부터 발생한 문제로… iOS 9는 물론 iOS 10에서도 고쳐지지 않았죠.

이쯤되니 OS 자체 버그가 아니라 의도된 것 같다는 생각이 듭니다. 의도된 것이 맞다면 어떤식으로 개발을 해야 되는 건지 모르겠네요.

그래서 사용한 임시 방법.

dismiss()를 override 해버리는 방법입니다.

// MARK: - Variable
var isDismiss: Bool = false

// MARK: - Override
public override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    if !self.isDismiss && (self.presentedViewController == nil || self.presentedViewController == self) {
        return
    }

    self.isDismiss = false
    super.dismiss(animated: flag, completion: completion)
}

// MARK: - Function
func close(animated: Bool, completion: (() -> Void)? = nil) {
    self.isDismiss = true
    self.dismiss(animated: animated, completion: completion)
}
// MARK: - Action
@IBAction func close(_ sender: UIButton) {
    self.close(animated: true)
}

편법이지만 제일 간단한 방법이죠…

Advertisements

‘아이슬란드 일주’ 5일만에 끝내기 – 3일차

어젯밤엔 어두워서 몰랐지만 외딴 곳에 있는 숙소의 경치가… 와…

보너스 마트에서 산 아침 거리로 핫도그를 만들어 먹고,

2016-10-05-08-05-35.jpg

경치를 즐기며 여유있게 드립 커피 한 잔.



출발 준비 완료! 




110716_1004_56.jpg

우선 에이일스타디르에서 주유를 하고

본격적으로 출발.

110716_1004_57.png

첫 목적지는 ‘세이디스피외르뒤르’입니다.

110716_1004_58.jpg
산으로 둘러 쌓여 있는 아주 멋진 이 항구 “마을”은 생선 가공업이 주산업이었지만 관광업으로 바꾸었다고 하네요.

그래도 항구 근처에 컨테이너들이 몇 있더군요.

마을을 둘러싼 산, 마을의 목조 건물들이 이미 아름다웠지만 거리 곳곳에서 관광객을 신경 쓴 모습도 볼 수 있었습니다.

110716_1004_59.png110716_1004_60.jpg110716_1004_61.jpg

다음 목적지는 회픈입니다. 점심 먹으러 ㄱㄱ

110716_1004_64.png

회픈 가는 길은 예상보다 오래 걸리고 말았습니다.
갤럭시 s7 엣지 핸드폰으로 네비게이션으로 사용했는데 무슨 이유인지 GPS가 튀면서 방향을 잘못 잡았습니다.

엉뚱한 길로 돌아가는 상황이 되었죠.

다행히 일행 중 한명이 상황은 눈치 챈 덕분에 몇시간을 더 돌아서 갈 상황은 막았습니다.

110716_1004_65.png110716_1004_66.jpg

비도 와서 속도 내기 힘든 상황에서 하루 일정을 다 망칠 뻔 했네요.

네비게이션을 새로 세팅하고 유턴하여 다시 출발.

그런데 한가지 더 난관이 기다리고 있었네요.

북쪽에서도 보지 못한 험한 도로를 만납니다. 1번 국도는 전체적으로 잘 닦인 도로라 생각했는데 곳곳에 구멍이 파진 험한 도로를 만납니다.

거기다…

엉뚱한 길로 가면서 많은 시간을 낭비했던지라 지도만 보고 1번 국도를 포기하고 거리가 가까운 도로를 선택했는데…

어차피 1번 국도도 험하니 벗어나서 다른 도로로 가도 상관이 없을 것 같았지만 잘못된 선택, 하필 산을 타는 도로였습니다.

비도 오는 상황에서 고도가 높아 지면서 안개가 짙어지고 시야가 완전히 가려집니다.

110716_1004_67.png

아이슬란드에서 경험한 최대의 위기가 아니었나 합니다.

한국에 돌아와서 알아 보니 매우 아름다운 풍경이었고 길 옆도 상상한 무시무시한 절벽이 아니었지만 저런 안개 속에선 전혀 알 수 없었죠. 조심 조심. 운전에만 초 집중.

110716_1004_68.jpg

드디어 시야가 확보된 도로.

무사히 회픈 도착.

110716_1004_69.jpg

회픈에 맛집으로 유명한 Kaffi Hornið에서 저녁에 가까운 점심 아닌 점심 식사 후 요쿨살론으로 이동합니다.

20161005_154954

20161005_161118.jpg20161005_162308.jpg20161005_162317.jpg

저녁거리를 회픈에서 마련하려 했지만 시간도 부족하고 점심이 많이 늦었기 때문에 바로 요쿨살론으로 향합니다.

가는 도중 제가 핸드폰 카메라 렌즈를 식당에 두고 와서 다시 되돌아 갑니다.

오늘 여러모로 제 갤럭시 핸드폰이 말썽이네요.

110716_1004_70.png110716_1004_71.jpg

2016-10-05-18-29-052016-10-05-18-34-5220161005_18260620161005_18314720161005_183359

빠르게 해가 지기 시작할때 요쿨살론에 도착합니다.

해가 완전히 지기 전에 도착하여 이런 멋진 빙산들을 볼 수 있어서 다행입니다. 안개 너머 더 많은 빙산들을 보지 못했지만 앞에 보이는 빙산들만으로도 너무 멋집니다.

110716_1004_72.png

요쿨살론을 떠날땐 이미 완전히 해가져서 우리가 피하고 싶었던 야간 운전을 또 하게 되네요.

아이슬란드의 다리는 희한하게도 2차선이 없더군요. 우리가 보았던 다리들은 1차선에, 중간 중간 앞에 오는 차량을 피할 수 있는 공간만 있었습니다.

그런 다리들을 건너 드디어 숙소에 도착.

110716_1004_73.jpg

날씨에… 여러가지 사건도 있어서 다들 피곤한지 저녁 생각 없이 다들 취침.

주석이 필요 없는 코드.key

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-002

주석 자체가 나쁜 것은 아니다. 개발자는 주석을 남기는 것을 귀찮아 한다. 그럼에도 주석을 작성해야 되겠다 생각이 들었다면 그것은 나쁜 코드를 작성하고 보완을 하려는 목적일 가능성이 매우 높다. 코드를 보완하는 것이 훨씬 낫다. 다시 말하지만 주석 자체가 나쁜 것은 아니다. 하지만 주석으로 보완하지 않는 코드를 작성하는 습관이 선행되어야 한다 주석을 잘 다는 습관은 그 다음에 익혀도 된다.

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-003

개발자라면 일정에 쫓겨 나쁜 코드를 작성한 후 나중에 수정해야지 라는 생각을 가진 경험이 있을 것이다. 그리고 개발자라면 그 ‘나중’이 단 한번도 온 적이 없다는 것을 경험으로 알 것이다.

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-004

선언 의도를 파악할 수 있는 이름, 의미가 있는 이름. 불필요하게 단순화 시킨 이름은 검색이 어렵다. 발음이 쉽지 않은 이름은 커뮤니케이션을 어렵게 한다. 동일한 행위에 대해서는 동일한 단어를 사용하는 것이 좋다. get receive fetch -> receive / 그러나 통일성을 위해 강박적으로 단어를 통일 시켜서도 안된다. 동일한 행위라도 차이가 있다면 구분을 해주어야 한다. add insert append

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-005%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-006

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-007

마지막으로 강조하고 싶은 것은 코드는 만들때 잘 만드는 것도 중요하지만 실상 코드는 수정, 추가를 거치면서 나쁜 코드로 가속화 된다. 남이 만든 코드든 자신이 만든 코드든 수정, 추가할때 더욱 유의해야 한다. pull 받은 코드는 push 할때 더욱 깨끗하게.

%ec%a3%bc%ec%84%9d%ec%9d%b4-%ed%95%84%ec%9a%94%ec%97%86%eb%8a%94-%ec%bd%94%eb%93%9c-008

반복된 디버깅에 지쳐 있다면 코드부터 뜯어 고치자. 같은 방식으로 개발하면서 버그가 발생하고 유지보수가 어렵다고 투덜 거리는 건 의미 없다.

WKWebView 사용 시 필수적으로 넣어줘야 하는Delegate 넷.

WKWebView를 사용한다면 아래의 넷은 반드시 넣어 주어야 한다. 복사->붙여 넣기 후 개발을 시작하면 된다.

우선, WKUIDelegate 셋.

func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping () -> Void) {
    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)
}

func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (Bool) -> Void) {
    let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in
        completionHandler(true)
    }))
    alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in
        completionHandler(false)
    }))

    self.present(alertController, animated: true, completion: nil)
}

func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping (String?) -> Void) {
    let alertController = UIAlertController(title: "", message: prompt, preferredStyle: .alert)
    alertController.addTextField { (textField) in
        textField.text = defaultText
    }
    alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in
        if let text = alertController.textFields?.first?.text {
            completionHandler(text)
        } else {
            completionHandler(defaultText)
        }
    }))

    alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in
        completionHandler(nil)
    }))

    self.present(alertController, animated: true, completion: nil)
}

이건 iOS 9.0 이후 지원이긴 한데… WKNavigationDelegate 하나.

public func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
    // 중복적으로 리로드가 일어나지 않도록 처리 필요.
    webView.reload()
}

앱이 백그라운드 상태에서 포그라운드로 돌아 올때 간혹 WKWebView가 하얀 화면으로 되어 있는 경우가 있는데, 보통 자바스크립트 등으로 체크해서 대응을 하고 있지만 iOS 9이상에선 지원하고 있다.